## 1. 数组名的本质
数组名在大多数情况下表示数组首元素的地址,但存在两个例外:
- sizeof(数组名):此时数组名表示整个数组,计算的是整个数组的大小(字节数)。
- &数组名:此时数组名表示整个数组,取出的是整个数组的地址。
示例代码
#include <stdio.h>
int main() {
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
printf("&arr[0] = %p\n", &arr[0]); // 首元素地址
printf("arr = %p\n", arr); // 首元素地址
printf("&arr = %p\n", &arr); // 整个数组的地址
// 地址偏移验证
printf("&arr[0]+1 = %p\n", &arr[0]+1); // +4字节(int)
printf("arr+1 = %p\n", arr+1); // +4字节
printf("&arr+1 = %p\n", &arr+1); // +40字节(整个数组大小)
return 0;
}
输出结果
&arr[0] = 0x7ffd2d4d3a20
arr = 0x7ffd2d4d3a20
&arr = 0x7ffd2d4d3a20
&arr[0]+1 = 0x7ffd2d4d3a24
arr+1 = 0x7ffd2d4d3a24
&arr+1 = 0x7ffd2d4d3a48
2. 使用指针访问数组
通过指针可以灵活访问数组元素,数组名 arr 和指针 p 是等价的:
int arr[10] = {0};
int *p = arr; // p指向数组首元素
遍历示例
for (int i = 0; i < 10; i++) {
scanf("%d", p + i); // 等价于 arr + i
printf("%d", *(p + i)); // 等价于 p[i] 或 arr[i]
}
3. 一维数组传参本质
数组传参时,传递的是首元素地址,而非整个数组。因此,函数内部无法通过 sizeof 计算数组长度。
示例代码
void test(int arr[]) { // 形参可写成 int *arr
int sz2 = sizeof(arr) / sizeof(arr[0]); // sz2=1(指针大小/元素大小)
printf("sz2 = %d\n", sz2);
}
int main() {
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
int sz1 = sizeof(arr) / sizeof(arr[0]); // sz1=10
test(arr); // 传递首元素地址
return 0;
}
输出结果
sz1 = 10
sz2 = 1
4. 冒泡排序核心思想
冒泡排序通过相邻元素的两两比较,将最大/最小值逐步“冒泡”到数组末端。
核心步骤
1.从第一个元素开始,依次比较相邻元素。
2.若前一个元素大于后一个元素,则交换。
3.每趟排序确定一个最大元素的位置。
4.重复 n-1 趟,直至完全有序。
5. 二级指针
指针变量也是变量,其地址存储在二级指针中。
int a = 10;
int *pa = &a; // 一级指针
int **ppa = &pa; // 二级指针
- ppa 存储 pa 的地址,*ppa 解引用得到 pa 的值(即 &a),**ppa 得到 a 的值。
6. 指针数组与模拟二维数组
指针数组是元素为指针的数组,可用于模拟二维数组。
int arr1[] = {1, 2, 3};
int arr2[] = {4, 5};
int *parr[] = {arr1, arr2}; // 指针数组
// 访问元素(模拟二维数组)
printf("%d\n", parr[0][1]); // 输出2
printf("%d\n", parr[1][0]); // 输出4
总结
1.数组名在大多数情况下是首元素地址,例外为 sizeof(arr) 和 &arr。
2.指针访问数组时,arr[i] 等价于 *(arr+i)。
3.数组传参本质传递指针,形参可写作数组或指针形式。
4.二级指针存储一级指针的地址。
5.指针数组的每个元素是指针,可模拟二维数组结构。