1、数组名作为指针
在表达式中使用数组名时,数组名会自动退化为指向首元素的指针。
#include <stdio.h> int main() { int arr[5] = {1, 2, 3, 4, 5}; // 打印数组的地址 printf("arr: %p\n", (void*)arr); printf("&arr[0]: %p\n", (void*)&arr[0]); // 比较数组名和首元素指针 if (arr == &arr[0]) { printf("arr == &arr[0] 为真\n"); } else { printf("arr != &arr[0] 为假\n"); } return 0; }
在大多数情况下,arr
会退化为 &arr[0]
,即指向数组首元素的指针。arr
和 &arr[0]
都指向数组的第一个元素的地址, 也就是arr == &arr[0]
。
2、&arr 和 arr 的区别
尽管 arr
和 &arr
在地址上是相同的,但它们的类型不同,因此在使用时需要注意。arr
退化为 int*
类型,指向数组的首元素。&arr
的类型是 int(*)[5]
,表示一个指向包含5个 int
的数组的指针。
#include <stdio.h> int main() { int arr[5] = {1, 2, 3, 4, 5}; printf("arr = %p\n", (void*)arr); // 打印数组首元素的地址 printf("&arr = %p\n", (void*)&arr); // 打印数组的地址(与arr相同) printf("&arr[0] = %p\n", (void*)&arr[0]); // 打印首元素的地址(与arr相同) printf("sizeof(arr) = %zu\n", sizeof(arr)); // 输出数组的总大小(20字节) printf("sizeof(&arr) = %zu\n", sizeof(&arr)); // 输出指针的大小(取决于系统,通常为8字节) return 0; }
arr
、&arr
和 &arr[0]
的值(地址)相同,因为它们都指向数组的第一个元素。sizeof(arr)
是整个数组的大小(20字节),而 sizeof(&arr)
是一个指针的大小(通常是8字节)。arr
是 int*
类型的指针,而 &arr
是 int(*)[5]
类型的指针,它们的类型不同。
3、不发生退化的情况
数组名不会总是退化为指针,如下面几种情况,
1)使用 sizeof 运算符
使用sizeof
运算符时,sizeof(arr)
会返回数组的总大小,而不是指针的大小。
#include <stdio.h> int main() { int arr[5] = {1, 2, 3, 4, 5}; printf("Size of arr: %lu\n", sizeof(arr)); // 输出数组的总大小 printf("Size of arr[0]: %lu\n", sizeof(arr[0])); // 输出数组中每个元素的大小 printf("Number of elements in arr: %lu\n", sizeof(arr) / sizeof(arr[0])); // 计算数组元素数量 return 0; }
2) 使用 & 运算符
使用&
运算符时,&arr
返回整个数组的地址,类型为 int(*)[5]
。
#include <stdio.h> int main() { int arr[5] = {1, 2, 3, 4, 5}; int *ptr = arr; // ptr 是指向数组第一个元素的指针,类型为 int* int (*arr_ptr)[5] = &arr; // arr_ptr 是指向整个数组的指针,类型为 int (*)[5] printf("Address of arr (using &arr): %p\n", (void*)&arr); printf("Address of arr (using arr): %p\n", (void*)arr); return 0; }
3) 字符串字面量初始化
在字符串字面量初始化时,例如 char arr[] = "hello";
会将整个字符串字面量复制到 arr
中。
#include <stdio.h> int main() { char arr[] = "hello"; // 字符串字面量 "hello" 被复制到 arr 中 printf("Array content: %s\n", arr); // 输出整个字符串 printf("Size of arr: %lu\n", sizeof(arr)); // 包含了空字符 '\0' return 0; }