数组名与指针
数组名在大多数表达式中会退化为指向首元素的指针,但数组名不是指针变量——它不能被赋值,不能自增。理解数组名与指针的异同,是掌握 C 语言数组和指针关系的基础。
数组名退化
数组名在表达式中通常退化为指向首元素的指针:
int arr[5] = {10, 20, 30, 40, 50};
int *p = arr; /* arr 退化为 &arr[0] */
printf("%d\n", *p); /* 10 */
/* 等价访问 */
printf("%d\n", arr[2]); /* 30 */
printf("%d\n", *(arr + 2)); /* 30 */
数组名不是指针
数组名在以下情况不退化:
sizeof 运算符:
int arr[5];
printf("%zu\n", sizeof(arr)); /* 20:整个数组的大小 */
printf("%zu\n", sizeof(int *)); /* 4 或 8:指针大小 */
取地址 &:
int arr[5];
int *p1 = arr; /* &arr[0],类型 int* */
int (*p2)[5] = &arr; /* 整个数组的地址,类型 int (*)[5] */
printf("%p\n", (void *)p1); /* 0x1000 */
printf("%p\n", (void *)p2); /* 0x1000 */
printf("%p\n", (void *)(p1 + 1)); /* 0x1004 */
printf("%p\n", (void *)(p2 + 1)); /* 0x1014:跳过整个数组 */
字符串初始化:
char str[] = "Hello"; /* 数组初始化,不是指针赋值 */
数组名不可修改
数组名不是可修改的左值:
int arr[5];
/* arr = NULL; */ /* 错误 */
/* arr++; */ /* 错误 */
int *p = arr;
p++; /* 合法 */
数组与指针参数
数组作为函数参数时退化为指针:
void func(int arr[])
{
printf("%zu\n", sizeof(arr)); /* sizeof(int*) */
}
void func2(int *arr) /* 等价 */
{
/* ... */
}
常见错误
数组赋值:
int a[5] = {1, 2, 3, 4, 5};
int b[5];
/* b = a; */ /* 错误:数组不可赋值 */
/* 正确 */
memcpy(b, a, sizeof(a));
sizeof 在函数中:
void func(int arr[])
{
int n = sizeof(arr) / sizeof(arr[0]); /* 错误!sizeof(arr) = sizeof(int*) */
}
数组名自增:
int arr[5];
/* arr++; */ /* 错误 */
最佳实践
- 理解数组名在表达式中的退化规则
- 用
sizeof(arr) / sizeof(arr[0])计算数组大小(只在声明作用域) - 数组作为参数时,始终传递大小
- 需要修改遍历位置时,用指针而非数组名
- 区分
arr(int*)和&arr(int (*)[N])