C 语言指针(3)(4)
本文为 C 语言指针系统学习笔记第三、四部分合集涵盖数组名本质、指针访问数组、一维 / 二维数组传参、冒泡排序、二级指针、指针数组、数组指针、字符指针、函数指针、函数指针数组、转移表计算器示例可直接运行一、数组名的本质最易混淆点核心结论数组名 数组首元素地址两个例外sizeof(数组名)数组名表示整个数组计算整个数组大小数组名数组名表示整个数组取出整个数组的地址#includestdio.h int main() { int arr[10] { 0 }; printf(arr %p\n, arr); printf(arr1 %p\n, arr 1); printf(arr[0] %p\n, arr[0]); printf(arr[0]1 %p\n, arr[0] 1); printf(arr %p\n, arr); printf(arr1 %p\n, arr 1); return 0; }arr和arr[0]一样首元素地址1 跳 4 字节arr是整个数组地址1 跳整个数组大小40 字节二、使用指针访问数组数组在内存中连续存放配合指针运算可轻松遍历数组。#includestdio.h int main() { int arr[10] { 0 }; int sz sizeof(arr) / sizeof(arr[0]); int* p arr; int i 0; // 输入 for (i 0; i sz; i) { scanf(%d, p i); } // 输出 for (i 0; i sz; i) { printf(%d , *(p i)); } return 0; }超级重点plaintextarr[i] *(arr i) *(i arr) i[arr][]只是下标操作符底层全是指针运算三、一维数组传参本质结论一维数组传参 → 本质是传递首元素地址 → 形参本质是指针所以下面三种写法完全等价void Print(int arr[10], int sz); void Print(int arr[], int sz); void Print(int* arr, int sz);大坑提醒// 错误写法 void Print(int arr[10]) { // 这里 sizeof(arr) 4/8 字节 int sz sizeof(arr) / sizeof(arr[0]); }数组传参后形参只是指针无法在函数内部求数组长度必须由主函数传进来。四、经典冒泡排序指针 数组综合实战思想两两相邻比较大的往后冒每一趟确定一个最大元素。#includestdio.h void bubble_sort(int arr[], int sz) { int i 0; for (i 0; i sz - 1; i) { int flag 1; int j 0; for (j 0; j sz - 1 - i; j) { if (arr[j] arr[j 1]) { int tmp arr[j]; arr[j] arr[j 1]; arr[j 1] tmp; flag 0; } } if (flag 1) break; } } void print_arr(int arr[], int sz) { int i 0; for (i 0; i sz; i) { printf(%d , arr[i]); } } int main() { int arr[] { 9,8,7,6,5,4,3,2,1,0 }; int sz sizeof(arr) / sizeof(arr[0]); bubble_sort(arr, sz); print_arr(arr, sz); return 0; }五、二级指针一级指针存变量地址二级指针存一级指针地址。int main() { int a 10; int* p a; // 一级指针 int** pp p; // 二级指针 printf(%p\n, *pp); // a printf(%d\n, **pp); // a 10 return 0; }六、指针数组存放指针的数组int* arr[10]; // 数组每个元素是 int* 指针指针数组模拟二维数组#includestdio.h int main() { int arr1[] { 1,2,3,4,5 }; int arr2[] { 2,3,4,5,6 }; int arr3[] { 3,4,5,6,7 }; int* arr[] { arr1,arr2,arr3 }; int i 0; for (i 0; i 3; i) { int j 0; for (j 0; j 5; j) { printf(%d , arr[i][j]); } printf(\n); } return 0; }七、字符指针与常量字符串#includestdio.h int main() { char arr[] abcdef; char* p1 arr; *p1 w; // 可以修改 const char* p2 abcdef; // *p2 w; // 错误常量字符串不可修改 printf(%s\n, p1); printf(%s\n, p2); return 0; }八、数组指针指向数组的指针语法int (*p)[10] arr;(*p)说明 p 是指针[10]说明指向10 个 int 的数组整体数组指针int main() { int arr[10]; int(*p)[10] arr; // 访问元素 int i 0; for (i 0; i 10; i) { printf(%d , (*p)[i]); } return 0; }九、二维数组传参本质二维数组名 第一行数组的地址 → 必须用数组指针接收void print(int (*arr)[5], int r, int c) { int i 0; for (i 0; i r; i) { int j 0; for (j 0; j c; j) { printf(%d , *(*(arr i) j)); } printf(\n); } } int main() { int arr[3][5] { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7} }; print(arr, 3, 5); return 0; }十、函数指针存放函数地址int Add(int x, int y) { return x y; } int main() { // 函数指针 int (*pf)(int, int) Add; // 调用 int ret pf(2, 3); printf(%d\n, ret); return 0; }Add和Add一样都是函数地址函数指针调用可以写pf(2,3)或(*pf)(2,3)十一、函数指针数组 转移表计算器实战把多个函数地址存到数组里实现菜单选择自动调用对应函数。#includestdio.h int Add(int x, int y) { return x y; } int Sub(int x, int y) { return x - y; } int Mul(int x, int y) { return x * y; } int Div(int x, int y) { return x / y; } void menu() { printf(***********************\n); printf(******1.add 2.sub******\n); printf(******3.mul 4.div******\n); printf(******0.exit ******\n); printf(***********************\n); } int main() { int input 0; int x 0, y 0; // 函数指针数组转移表 int (*pfArr[5])(int, int) { 0,Add,Sub,Mul,Div }; do { menu(); printf(请选择); scanf(%d, input); if (input 1 input 4) { printf(请输入两个操作数); scanf(%d %d, x, y); int ret pfArr[input](x, y); printf(结果%d\n, ret); } else if (input 0) { printf(退出计算器\n); } else { printf(输入错误\n); } } while (input); return 0; }本章总结数组名 首元素地址sizeof、 数组名例外数组传参 传地址 → 形参是指针指针数组存放指针的数组数组指针指向数组的指针二级指针存储一级指针地址函数指针存储函数地址函数指针数组 转移表可做菜单、命令分发