深入理解C语言指针(二):数组名、二级指针与指针数组

深入理解C语言指针(二):数组名、二级指针与指针数组
Lichermione深入理解C语言指针(二)
1. 数组名的含义
多数表达式中,数组名会转换为指向首元素的指针:
1 | int arr[5] = {1, 2, 3, 4, 5}; |
但有两个典型例外:
sizeof(arr)中,arr表示整个数组;&arr中,取得的是整个数组的地址。
1 | printf("%zu\n", sizeof(arr)); // 5 * sizeof(int) |
arr 与 &arr 的数值地址看起来相同,但类型不同。arr + 1 跨过一个 int,&arr + 1 跨过整个数组。
2. 使用指针访问数组
1 | for (int i = 0; i < 5; ++i) |
arr[i] 定义上等价于 *(arr + i)。为了可读性,普通数组遍历通常仍推荐下标写法。
3. 一维数组传参的本质
1 | void print_array(const int arr[], int size); |
以上两个函数声明等价。数组传参后,函数得到的是首元素地址,不知道原数组有多少元素,因此长度必须额外传递。
4. 冒泡排序
1 | void bubble_sort(int arr[], int size) |
平均与最坏时间复杂度为 O(n²),增加交换标记后,有序数组的最好情况可提前结束。
5. 二级指针
二级指针保存一级指针的地址:
1 | int value = 10; |
常见用途包括:
- 函数中修改调用者的指针;
- 管理动态二维结构;
- 处理字符串数组和命令行参数。
1 | void reset_pointer(int **pp, int *target) |
6. 指针数组
指针数组首先是数组,数组中的每个元素都是指针:
1 | int a = 1, b = 2, c = 3; |
int *arr[3] 与数组指针 int (*p)[3] 完全不同。判断方法是先看变量名与谁结合:arr 先与 [] 结合,所以是数组;p 被括号包裹并先与 * 结合,所以是指针。
7. 指针数组模拟二维数组
1 | int row1[] = {1, 2, 3}; |
这种结构的每一行可以位于不同内存区域,行长度也可以不同。它不同于真正连续存储的 int matrix[3][3]。
8. 总结
数组名、数组指针、指针数组和二级指针名称相近但结构不同。分析声明时先找到变量名,再按优先级向外阅读,同时结合它实际指向的对象判断是否合法。