1.一维数组名
1.1除了两种特殊情况外,都是指向数组第一个元素的指针
1.1.1特殊情况1 sizeof 统计数组长度
1.1.2特殊情况2 对数组名取地址,数组指针,步长整个数组长度
1.2数组名是指针常量,指针的指向不可以修改的,而指针指向的值可以改
1.3传参数时候,int arr[] 可读性更高
1.4数组索引下标可以为负数
// 打印数组
void printArray(int arr[], int len) // int arr[]等价于 int *arr,前者更好,因为可读性更高
{
for (size_t i = 0; i < len; i++)
{
printf("%d\n", arr[i]);
}
}
/*
有两种特殊情况,一维数组名不是指向第一个元素是指针
1.sizeof
2.对数组名取地址,得到的数组指针,步长是整个数组长度
*/
void test01()
{
// 一维数组名是不是指针?
int arr[5] = { 1,2,3,4,5 }; // 20
printf("%d\n", sizeof(arr));
printf("%d\n", &arr);
printf("%d\n", &arr + 1); // 两个相差了一个数组的长度被称为数组指针
//-1563427552
//-1563427532
int len = sizeof(arr) / sizeof(int);
printArray(arr, len);
// arr数组名,它是一个指针常量,指针的指向不可以修改,而指针指向的值可以修改 int * const a
//arr[0] = 1000; // 可以修改
//arr = NULL; // 会报错,不可以修改
// 数组索引可不可以为负数
int* p = arr;
p = p + 3;
printf("%d\n", p[-1]); // 3 *(p-1)
}
2.数组指针的定义方式
2.1先定义出数组类型,再通过类型定义数组指针变量
2.1.1typedef int(ARRARY_TYPE)[5];//ARRARY_TYPE 代表存放5个int类型元素的数组 的数组类型
2.2先定义数组指针类型,再通过类型定义数组指针变量
2.2.1typedef int(*ARRARY_TYPE)[5];
2.3直接定义数组指针变量
2.3.1int(* p )[5] = &arr;
/* 数组指针的定义方式
1.先定义数组类型,再通过类型定义数组指针
2.先定义数组指针的类型,再通过类型定义在指针
3.直接定义数组指针
*/
void test01()
{
int arr[5] = { 1,2,3,4,5 }; // 先定义数组类型
typedef int(ARRAY_TYPE)[5]; // ARRAY_TYPE代表存放5个int类型元素的数组 的数组类型
ARRAY_TYPE arr2;
for (size_t i = 0; i < 5; i++)
{
arr2[i] = i + 100;
}
for (size_t i = 0; i < 5; i++)
{
printf("%d\n", arr2[i]);
}
ARRAY_TYPE* arrP = &arr;
// *arrP = arr = 数组名
for (size_t i = 0; i < 5; i++)
{
printf("%d\n", (*arrP)[i]);
}
}
void test02()
{
int arr[5] = { 1,2,3,4,5 };
typedef int(*ARRAY_TYPE)[5]; // 直接就是一个指针
ARRAY_TYPE arrP = &arr;
for (size_t i = 0; i < 5; i++)
{
printf("%d\n", (*arrP)[i]);
}
}
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]);
}
}
3.二维数组名
3.1二维数组名 除了两种特殊情况外,是指向第一个一维数组的 数组指针
3.2两种特殊情况
3.2.1sizeof 统计二维数组大小
3.2.2对数组名称取地址 int(*p)[3][3] = &arr
3.3二维数组做函数参数
3.3.1//void printArray(int (*array)[3], int row, int col)
3.3.2//void printArray(int array[][3], int row ,int col)
3.3.3void printArray(int array[3][3], int row ,int col) 可读性比较高
3.4数组指针 和 指针数组?
3.4.1数组指针: 指向数组的指针
3.4.2指针数组: 由指针组成数组
/*
除了两种特殊情况外,二维数组名称是 指向第一个一维数组的数组指针
1.sizeof
2.对数组名取地址&arr 获取的是二维数组的 数组指针 int(*p)[3][3] = &arr;
*/
void test01()
{
int arr[3][3] = {
{1,2,3} ,
{4,5,6},
{7,8,9} // 最后一行‘,’可加可不加
};
/*int arr[3][3] = { 1,2,3,4,5,6,7,8,9 };
int arr[][3] = { 1,2,3,4,5,6,7,8,9 };*/
printf("%d\n", sizeof(arr)); // 36
//2
//int(*p)[3][3] = &arr;
int(*Array)[3] = arr;
// 访问二维数组中的6这个元素
printf("%d\n", arr[1][2]); // 给人看
printf("%d\n", *(*(Array + 1) + 2)); // 给机器看
}
// array[3][3] 等价于一维数组指针 int(*array)[3]
void printArray(int array[3][3], int row, int col) // int array[][3]
{
for (size_t i = 0; i < row; i++)
{
for (size_t j = 0; j < col; j++)
{
//printf("%d ", array[i][j]); // 给人看
printf("%d ", *(*(array + i) + j) ); // 给机器看
}
printf("\n");
}
}
// 二维数组做函数的参数
void test02()
{
int arr[3][3] = {
{1,2,3} ,
{4,5,6},
{7,8,9} // 最后一行可加可不加
};
printArray(arr, 3, 3);
}
4.指针数组排序
4.1选择排序
4.1.1例如从小到大
4.1.2开始认定最小值下标为i,从j = i+1的位置起找真实最小值下标,如果计算的真实最小值下标与i不等,互换元素
4.2利用选择排序实现指针数组 从大到小排序
4.2.1字符串对比
4.2.2if ( strcmp(pArr[max],pArr[j]) == -1)
/*
选择排序法:
1.假设第一个数组最小,找到最小的数字的下标
2.将最小的数字和原来的数字交换
3.循环
*/
void mySort(int arr[], int len)
{
for (size_t i = 0; i < len; i++)
{
int min = i; // 记录最小值下标为i
for (int j = i + 1; j < len; j++)
{
if (arr[min] > arr[j])
{
// 更新真实最小值下标
min = j;
}
}
// 判断真实最小值下表是否与开始认定的i相等,如果不等,交换元素
if (i != min)
{
int temp = arr[i];
arr[i] = arr[min];
arr[min] = temp;
}
}
}
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);
mySort(arr, len);
printArray(arr, len);
}
void selectSort(char** pArr, int len)
{
for (size_t i = 0; i < len; i++)
{
int max = i;
for (size_t j = 0; 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 printArray2(char **pArr, int len)
{
for (size_t i = 0; i < len; i++)
{
printf("%s\n", pArr[i]);
}
}
void test02()
{
// 对指针数组进行排序,排序的算法利用 选择排序 从大到小
char* pArray[] = { "bbb","aaa","ccc","fff","ddd" };
int len = sizeof(pArray) / sizeof(char*);
selectSort(pArray, len);
printArray2(pArray,len);
}
5.结构体基本概念
5.1加typedef 可以给结构体起别名
5.2不加typedef ,可以直接创建一个结构体变量
5.3结构体声明 可以是匿名
5.4在栈上创建和在堆区创建结构体
5.5在栈上和堆区创建结构体变量数组
/*************************结构体的定义******************************************/
struct Person
{
char name[64];
int age;
};
//typedef struct Person myPerson;
//typedef struct Person
//{
// char name[64];
// int age;
//}myPerson;
//struct Person2
//{
// char name[64];
// int age;
//}myPerson2; // 已经是一个结构体变量
//myPerson2.age = 100;
//struct Person2
//{
// char name[64];
// int age;
//}myPerson2={"aaa",12}; // 已经是一个结构体变量
//printf("姓名:%s 年龄:%d\n", myPerson2.name, myPerson2.age);
// 匿名结构体
//struct
//{
// char name[64];
// int age;
//}myPerson3 = {"bbb",14}; // 一般不这样使用
/*****************结构体创建************/
void test04()
{
//创建在栈上
struct Person p = { "aaa",10 };
printf("姓名:%s 年龄:%d\n", p.name, p.age);
// 创建在堆区
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("姓名:%s 年龄:%d\n", personArray[i].name, personArray[i].age);
}
}
void test05()
{
// 在栈上分配内存
struct Person persons[] =
{
{"aaa",1},
{"bbb", 2},
{"ddd", 3},
};
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 = 18 + i;
}
printArray(pArray, 4); // 这里的4只能写不能算出来
if (pArray != NULL)
{
free(pArray);
pArray = NULL;
}
}
6.结构体深浅拷贝
6.1系统提供的赋值操作是浅拷贝 – 简单值拷贝,逐字节拷贝
6.2如果结构体中有属性创建在堆区,就会出现问题,在释放期间,一段内存重复释放,一段内存泄露
6.3解决方案:自己手动去做赋值操作,提供深拷贝
结构体在栈上
结构体在堆上
struct Person
{
char name[64];
int age;
};
void test01()
{
struct Person p1 = { "Tom",18 };
struct Person p2 = { "Jerry " };
printf("p1的姓名:%s\n 年龄:%d\n", p1.name, p1.age);
printf("p2的姓名:%s\n 年龄:%d\n", p2.name, p2.age);
p1 = p2;
printf("p1的姓名:%s\n 年龄:%d\n", p1.name, p1.age);
printf("p2的姓名:%s\n 年龄:%d\n", p2.name, p2.age); // 打印出来都是Jerry
}
struct Person2
{
char * name;
int age;
};
void test02()
{
struct Person2 p1;
p1.name = malloc(sizeof(char) * 64);
strcpy(p1.name, "Tom");
p1.age = 18;
struct Person2 p2;
p2.name = malloc(sizeof(char) * 128);
strcpy(p2.name, "Jerry");
p2.age = 28;
printf("p1的姓名:%s\n 年龄:%d\n", p1.name, p1.age);
printf("p2的姓名:%s\n 年龄:%d\n", p2.name, p2.age);
//p1 = p2; // 系统提供的赋值操作是简单的浅拷贝,我们需要手动赋值,提供深拷贝
/********************* 手动赋值************/
// 1.先释放原来的堆区内存(防止内存不够用)
if (p1.name != NULL)
{
free(p1.name);
p1.name = NULL;
}
// 2.在堆区创建内存
p1.name = malloc(strlen(p2.name) + 1);
strcpy(p1.name, p2.name);
p1.age = p2.age;
/********************************************/
printf("p1的姓名:%s\n 年龄:%d\n", p1.name, p1.age);
printf("p2的姓名:%s\n 年龄:%d\n", p2.name, p2.age);
if (p1.name != NULL)
{
free(p1.name);
p1.name = NULL; // 这个时候堆区的内存已经释放
}
if (p2.name != NULL)
{
free(p2.name);
p2.name = NULL; // 这里面堆区内容重复释放,而且有一个堆区的内存没有释放,会造成内存泄露
}
}
7.结构体嵌套一级指针练习
7.1在堆区创建一个 结构体指针数组
7.1.1malloc(sizeof(struct Person *) *3 )
7.2在堆区创建出结构体变量
7.2.1malloc(sizeof(struct Person))
7.3在堆区创建出具体姓名
7.3.1malloc(sizeof(char )*64);
7.4打印数据
7.5释放数组
struct Person
{
char* name;
int age;
};
struct Person** allocateSpace()
{
struct Person** temp = malloc(sizeof(struct Person*) * 3); // 三个malloc对应三个free
for (size_t i = 0; i < 3; i++)
{
//创建结构体内存
temp[i] = malloc(sizeof(struct Person));
// 将结构体姓名创建在堆区
temp[i]->name = malloc(sizeof(char) * 64);
// 给姓名赋值
sprintf_s(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("姓名:%s 年龄:%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)
{
printf("%s被释放了\n", pArray[i]->name);
free(pArray[i]->name);
pArray[i]->name = NULL;
}
free(pArray[i]);
pArray = NULL;
}
free(pArray);
pArray = NULL;
}
void test01()
{
struct Person** pArray = NULL;
pArray = allocateSpace();
// 打印数组
printPerson(pArray, 3);
// 释放内存空间
freeSpace(pArray, 3);
pArray = NULL;
}