C++笔记day17 数组、指针数组、结构体

164 阅读1分钟

一维数组名

除了两种特殊情况外,都是指向数组第一个元素的指针

特殊情况1   sizeof 统计数组长度

特殊情况2   对数组名取地址,数组指针,步长整个数组长度

数组名是指针常量,指针的指向不可以修改的,而指针指向的值可以改

传参数时候,int arr[]  可读性更高

数组索引下标可以为负数

示例

//int arr[]可读性更高
void printArray(int arr[], int len)//int arr[] 等价于 int *arr
{
	for (size_t i = 0; i < len; i++)
	{
		printf("%d\n", arr[i]);
	}
}

void test01() 
{
	//一维数组名是不是指针?不一定是
	int arr[5] = { 1,2,3,4,5 };
	printf("%d\n", sizeof(arr));

	//有两种特殊情况,一维数组名不是 指向第一个元素的指针
	//1. sizeof
	//2. 对数组名取地址,得到数组指针,步长是整个数组长度
	printf("%d\n", &arr);
	printf("%d\n", &arr + 1);
	//int *p =arr;
	int len = sizeof(arr)/sizeof(arr[0]);
	printArray(arr, len);
	//arr数组名 它是一个指针常量,指针的指向是不可以修改的,而指针指向的值是可以改的int *const a;
	// arr[0]=1000;
	//arr =NULL;

	//数组索引 可不可以为负数:可以放负数
	int* p = arr;
	p = p + 3;
	printf("%d\n", p[-1]);//给人看的
	printf("%d\n", *(p - 1));//给机器看的,二者等价
int main(void)
{
	test01();
	system("pause");
	return EXIT_SUCCESS;
}

数组指针的定义方式

先定义出数组类型,再通过类型定义数组指针变量

typedef int(ARRARY_TYPE)[5];//ARRARY_TYPE 代表存放5个int类型元素的数组 的数组类型

先定义数组指针类型,再通过类型定义数组指针变量

typedef int(*ARRARY_TYPE)[5];

直接定义数组指针变量

int(* p )[5] = &arr;

示例

//数组指针的定义方式
//1. 先定义数组类型,在通过类型定义数组指针
void test01() 
{
	int arr[5] = { 1,2,3,4,5 };
	typedef int(ARRARY_TYPE)[5];//ARRARY_TYPE代表存放5个int类型元素的数组 的数组类型
	//ARRARY_TYPE arr2; 
	//for (size_t i = 0; i < 5; i++)
	//{
	//	arr2[i] = i + 10;
	//}
	//for (size_t i = 0; i < 5; i++)
	//{
	//	printf("%d\n", arr2[i]);
	//}
	ARRARY_TYPE* arrP = arr; //拿到了数组指针
	//*arrP ==arr ==数组名
	for (size_t i = 0; i < 5; i++)
	{
		printf("%d\n", (*arrP)[i]);
	}
}
//2. 先定义数组指针的类型,再通过类型定义数组指针; 
void test02() 
{
	int arr[5] = { 1,2,3,4,5 };
	typedef int(*ARRARY_TYPE)[5];
	ARRARY_TYPE arrP = &arr;
	for (size_t i = 0; i < 5; i++)
	{
		printf("%d\n", (*arrP)[i]);
	}
}
//3. 直接定义数组指针变量
void test03() 
{
	int arr[5] = { 1,2,3,4,5 };
	int(*p)[5] = &arr;
	for (size_t i = 0; i < 5; i++)
	{
		printf("%d\n", (*p)[i]);
	}
}
int main(void)
{
	test01();
	system("pause");
	return EXIT_SUCCESS;
}

二维数组名

二维数组名 除了两种特殊情况外,是指向第一个一维数组的 数组指针

两种特殊情况
    sizeof 统计二维数组大小

    对数组名称取地址  int(*p)[3][3] = &arr

二维数组做函数参数

//void printArray(int (*array)[3], int row, int col)
//void printArray(int array[][3], int row ,int col)
//void printArray(int array[3][3], int row ,int col)  可读性比较高

数组指针 和  指针数组?

数组指针: 指向数组的指针

指针数组: 由指针组成数组

指针数组排序

选择排序

例如从小到大


    开始认定最小值下标为i,从j = i+1的位置起找真实最小值下标,如果计算的真实最小值下标与i不等,互换元素
    

image.png

示例

void selectSort(int arr[], int len)
{
	for (size_t i = 0; i < len; i++)
	{
		int min = i;//记录最小值下标为i;
		for (size_t j = i+1; j < len; j++)
		{
			if (arr[min] > arr[j])
			{
				//更新真实最小值下标
				min = j;
			}
		}
		//判断真实最小值下标是否与开始认定改的i相等,如果不等,交换匀速
		if (i!=min)
		{
			arr[min] = arr[i] + arr[min];
			arr[i] = arr[min] - arr[i];
			arr[min] = arr[min] - arr[i];
		}
	}
}
void printArray(int arr[], int len)
{
	for (size_t i = 0; i < len; i++)
	{
		printf("%d\n", arr[i]);
	}
}
void test01()
{
	//从小到大,利用选择排序
	int arr[] = { 2,5,1,3,4 };
	int len = sizeof(arr) / sizeof(int);
	selectSort(arr, len);
	printArray(arr, len);

}

int main(void)
{
	test01();
	system("pause");
	return EXIT_SUCCESS;
}

利用选择排序实现 指针数组 从大到小排序

字符串对比

if ( *strcmp*(pArr[max],pArr[j]) == -1)

示例

//void selectSort(char **pArr,int int len)
void mySelectSort(char* pArr[], int len) 
{
	for (size_t i = 0; i < len; i++)
	{
		int max = i;
		for (size_t j = i+1; j < len; j++)
		{
			if (strcmp(pArr[max],pArr[j])==-1)
			{
				max = j;
			}
		}
		if (i !=max)
		{
			char* tmp = pArr[i];
			pArr[i] = pArr[max];
			pArr[max] = tmp;
		}
	}
}
void printPArr(char** pArr, int len) 
{
	for (size_t i = 0; i < len; i++)
	{
		printf("%s\n", pArr[i]);
	}
}
void test02()
{
	//对指针数组进行排序,排序的算法利用选择排序
	char* pArray[] = { "aaa","ccc","fff","eee","ddd","bbb" };
	int len = sizeof(pArray) / sizeof(pArray[0]);
	printf("len =%d\n", len);
	mySelectSort(pArray, len);
	printPArr(pArray, len);

}

int main(void)
{
	test02();
	system("pause");
	return EXIT_SUCCESS;
}

结构体基本概念

加typedef 可以给结构体起别名

不加typedef ,可以直接创建一个结构体变量

结构体声明 可以是匿名

在栈上创建和在堆区创建结构体

在栈上和堆区创建结构体变量数组

示例

//定义方法1
//struct Person 
//{
//	char name[64];
//	int age;
//};
//定义方法2
typedef struct Person
{
	char name[64];
	int age;
} myPerson;
//定义方法3
struct Person2
{
	char name[64];
	int age;
} myPerson2 = {"Jim",23};
void test01() 
{
	struct Person p = { "tom",18 };
	myPerson p1 = { "andy",18 };
	printf("姓名:%s 年龄%d\n", myPerson2.name, myPerson2.age);
}
//匿名结构体
struct 
{
	char name[64];
	int age;
} myPerson3 = {"bbb",18};//比较少,不能再创建新的结构体变量
void test02() 
{
	printf("姓名:%s 年龄%d\n", myPerson3.name, myPerson3.age);
}
//结构体创建
void test04() 
{
	//创建在栈上
	struct Person p = { "aaa",10 };
	//创建在堆区
	struct Person* p2 = malloc(sizeof(struct Person));//没法直接赋初值
	strcpy(p2->name, "bbb");//采用这种方法对堆区的结构体变量赋初值
	p2->age = 20;

	printf("姓名: %s 年龄:%d\n", p2->name, p2->age);

	if (p2 != NULL) 
	{
		free(p2);
		p2 = NULL;
	}
}
void printArray(struct Person personArray[], int len) 
{
	for (size_t i = 0; i < len; i++)
	{
		printf("name:%s age:%d\n", personArray[i].name, personArray[i].age);
	}
}
//结构体变量数组创建
void test05() 
{
	//在栈上分配内存
	struct Person persons[] = {
		{"aaa",10},{"bbb",18},{"vvvv",21}
	};
	int len = sizeof(persons) / sizeof(struct Person);
	printArray(persons, len);

	//在堆区分配内存
	struct Person* pArray = malloc(sizeof(struct Person) * 4);
	//指针不能为空要在这里赋初值
	for (size_t i = 0; i < 4; i++)
	{
		sprintf(pArray[i].name, "name_%d", i + 1);
		pArray[i].age = i + 18;
	}
	printArray(pArray, 4);
	if (pArray != NULL) 
	{
		free(pArray);
		pArray = NULL;
	}
}
int main(void)
{
	test05();
	system("pause");
	return EXIT_SUCCESS;
}

结构体深浅拷贝

浅拷贝:逐字节拷贝

系统提供的赋值操作是 浅拷贝 – 简单值拷贝,逐字节拷贝

image.png

如果结构体中有属性 创建在堆区,就会出现问题,在释放期间,一段内存重复释放,一段内存泄露

image.png

解决方案:自己手动去做赋值操作,提供深拷贝

结构体嵌套一级指针练习

在堆区创建一个 结构体指针数组

malloc(sizeof(struct Person *) *3 )

在堆区创建出结构体变量

malloc(sizeof(struct Person))

在堆区创建出具体姓名

malloc(sizeof(char )*64);

打印数据

释放数组

示例

struct Person 
{
	char* name;
	int age;
};
struct Person** allocateSpace() 
{
	struct Person **temp=malloc(sizeof(struct Person*) * 3);
	for (size_t i = 0; i < 3; i++)
	{
		//创建结构体内存
		temp[i] = malloc(sizeof(struct Person));

		//将结构体姓名 创建在堆区
		temp[i]->name = malloc(sizeof(char) * 64);
		
		//给姓名赋值
		sprintf(temp[i]->name, "name_%d", i + 1);
		temp[i]->age = 18 + i;
	}
	return temp;
}
void printPerson(struct Person** pArray, int len) 
{
	for (size_t i = 0; i < len; i++)
	{
		printf("name:%s age:%d\n", pArray[i]->name, pArray[i]->age);
	}
}

void freeSpace(struct Person** pArray, int len) 
{
	if (pArray == NULL) 
	{
		return;
	}
	if (len<=0)
	{
		return;
	}
	for (size_t i = 0; i < 3; i++)
	{
		if (pArray[i]->name != NULL) 
		{
			free(pArray[i]->name);
			pArray[i]->name = NULL;
		}
		free(pArray[i]);
		pArray[i] = NULL;
	}
	free(pArray);
	pArray = NULL;
}

void test01() 
{
	struct Person** pArray = NULL;
	pArray=allocateSpace(); 
	//打印数组
	printPerson(pArray,3);
	//释放内存
	freeSpace(pArray, 3);
	pArray = NULL;
}
int main(void)
{
	test01();
	system("pause");
	return EXIT_SUCCESS;
}