4. 指针与数组的关系
任务目标
在嵌入式C开发中,数组名与指针常被混用,但二者本质不同。本案例通过一个最小可运行程序,演示如何使用指针遍历数组,并明确数组名与指针在类型、可修改性和sizeof运算上的差异。
核心代码
#include <stdio.h>
int main(void) {
int arr[5] = {10, 20, 30, 40, 50};
int *p = arr; // 数组名arr隐式转换为指向首元素的指针
// 1. 用指针遍历数组
printf("指针遍历结果: ");
for (int i = 0; i < 5; i++) {
printf("%d ", *(p + i)); // p+i 指向第i个元素,*解引用取值
}
printf("\n");
// 2. 数组名与指针的异同对比
printf("arr[2] = %d, *(p+2) = %d\n", arr[2], *(p + 2)); // 下标与指针等价
// 数组名是常量地址,不能自增;指针是变量,可以自增
p++; // 合法:p指向arr[1]
printf("p自增后指向: %d\n", *p);
// sizeof差异:数组名代表整个数组,指针只代表指针本身
printf("sizeof(arr) = %zu (整个数组字节数)\n", sizeof(arr));
printf("sizeof(p) = %zu (指针变量字节数)\n", sizeof(p));
return 0;
}
编译与运行
# 使用gcc编译(嵌入式交叉编译器用法相同)
gcc -o arr_ptr_demo arr_ptr_demo.c
# 运行
./arr_ptr_demo
验证方法与判定标准
- 指针遍历正确性:程序输出
10 20 30 40 50,说明通过*(p+i)成功访问每个元素。 - 下标等价性:
arr[2]与*(p+2)均输出30,验证a[i]本质是*(a+i)的语法糖。 - 可修改性差异:
p++编译通过并输出20;若尝试arr++则编译报错,因为数组名是常量地址。 - sizeof差异:在32位系统上
sizeof(arr)输出20(5个int×4字节),sizeof(p)输出4(指针本身大小)。在64位系统上后者为8。该差异直接证明数组名不是指针变量。
关键说明
数组名在表达式中会隐式转换为指向首元素的指针(例外:作为sizeof、&操作数时),但数组名本身是地址常量,不能作为左值赋值。指针变量则保存地址且可重新指向。在嵌入式场景中,理解此差异可避免误用sizeof计算数组长度(如sizeof(arr)/sizeof(arr[0])只能用于真实数组,不能用于已退化为指针的函数参数)。