【C语言】深入理解指针3 目录1.数组名的理解2.使用指针访问数组3.一维数组传参的本质4.冒泡排序5.二级指针6.指针数组7.指针数组模拟二维数组1.数组名的理解假设存在数组arr:int arr[10] { 1,2,3,4,5,6,7,8,9,10};1.数组名是数组首元素低的地址int main() { int arr[10] { 1,2,3,4,5,6,7,8,9,10 }; //数组名是数组首元素的地址 printf(%p\n, arr[0]); printf(%p\n, arr); return 0; }2.特殊情况1sizeof中单独放数组名表示整个数组计算的是整个数组的大小2arr数组名不退化取出的是整个数组的地址类型是 int(*)[10]但是打印出来的地址和arr是一样的那么arr和arr的区别是什么int main() { int arr[10] { 1,2,3,4,5,6,7,8,9,10 }; printf(首元素的地址 %p\n, arr); printf(整个数组的地址 %p\n, arr); printf(首元素的地址1 %p\n, arr1);//4 printf(整个数组的地址1 %p\n, arr1);// 0x28 - 40因为跳过了整个数组 return 0; }arr是首元素的地址1就是跳过一个元素arr是数组的地址1就是跳过整个数组2.使用指针访问数组代码举例int main() { int arr[10] { 0 }; int sz sizeof(arr) / sizeof(arr[0]); int* p arr; int i 0; for (i 0;i 10;i) { *p i 1; p; } p arr; for (i 0;i 10;i) { printf(%d ,*(pi)); } return 0; }这里arr和p是等价的那我们可以用 arr[i] 访问数组的元素那p[i]是否也可以#include stdio.h int main() { int arr[10] { 0 }; int* p arr; int sz sizeof(arr) / sizeof(arr[0]); //输入 int i 0; for (i 0;i sz;i) { scanf(%d, pi); //scanf(%d, arri);也可以这样写 } //输出 for (i 0;i sz;i) { printf(%d , p[i]); } return 0; }由上面代码可以看出p[i] 等价于 *(pi)3.一维数组传参的本质本质上数组传参传递的是数组首元素的地址代码举例test(int arr[10])//数组降级为指针虽然写成数组形式但本质上还是指针 { size_t sz sizeof(arr) / sizeof(arr[0]);//不能用参数部分的数组来计算数组的元素个数 } int main() { int arr[10] { 1,2,3,4,5,6,7,8,9,10 }; test(arr); return 0; }在上述代码中当把数组名作为参数传参时形参即使写成数组形式本质上也是指针sizeof里虽然单独放了数组名但arr作为参数会被调整为指针所以在这里sizeof(arr)计算的是一个地址的大小而不是数组的大小4.冒泡排序#include stdio.h void bubble_sort(int arr[], size_t sz) { int i 0; // 外层循环控制趟数共需要 sz-1 趟 for (i 0; i sz - 1; i) { int flag 1;// 假设本趟已经有序没有交换发生 int j 0; // 内层循环进行相邻元素的比较与交换 // 每趟比较的范围递减sz-1-i因为每趟结束最大值已“冒泡”到末尾 for (j 0; j sz - 1 - i; j) { if (arr[j] arr[j 1]) // 不满足升序则交换 { flag 0;// 发生了交换说明数组尚不完全有序 int tmp arr[j]; arr[j] arr[j 1]; arr[j 1] tmp; } } // 若经过一整趟比较后flag 仍为 1说明没有发生任何交换 // 即数组已经有序可以提前结束排序提高效率 if (flag 1) { break; } } } void print_arr(int arr[], size_t sz) { int i 0; for (i 0; i sz; i) { printf(%d , arr[i]); } printf(\n); } int main() { int arr[] {1, 3, 5, 7, 2, 4, 8, 6, 9, 10}; size_t sz sizeof(arr) / sizeof(arr[0]); // 调用冒泡排序 bubble_sort(arr, sz); // 打印排序后的数组 print_arr(arr, sz); return 0; }5.二级指针二级指针是指向指针的指针存储的是一个指针变量的地址int main() { int a 10; int* pa a;//一级指针变量 int** ppa pa;//二级指针变量,也是变量专门用来存放一级指针变量的地址//也可以有三级四级指针变量 //ppa找到n // *pa a //**ppa a; printf(%d , **ppa); return 0; }图解ppa的类型是 int* *是指向int*的指针ppa存储的是指针变量p的地址p解引用过程ppa→得到p的地址*ppa→得到p的值也就是a的地址等价于p**ppa→得到a的值等价于*p也就是106.指针数组存放指针数据的数组数组的每个元素都是指针类代码举例int *arr[5]; // arr 是一个有 5 个元素的数组每个元素都是 int* char *strs[3]; // strs 是一个有 3 个元素的数组每个元素都是 char*7.指针数组模拟二维数组#include stdio.h int main() { // 定义三个一维数组模拟矩阵的三行数据 int arr1[5] { 1, 2, 3, 4, 5 }; int arr2[5] { 2, 3, 4, 5, 6 }; int arr3[5] { 3, 4, 5, 6, 7 }; // 定义一个指针数组每个元素指向一个一维数组模拟二维数组的行指针 // arr 的类型是 int* [3]即包含 3 个 int* 的数组 // 数组名 arr1, arr2, arr3 在此退化为指向各自首元素的 int* 指针 int* arr[3] { arr1, arr2, arr3 }; int i 0; // 外层循环遍历指针数组的每一个元素每一行 for (i 0; i 3; i) { int j 0; // 内层循环遍历当前行中的每一个整数元素 // arr[i] 是第 i 行的首地址int*arr[i][j] 等价于 *(arr[i] j) for (j 0; j 5; j) { printf(%d , arr[i][j]); } printf(\n); } return 0; }