指针数组与数组指针的区别
#include int main(){ // 1. 指针数组 (Array of Pointers) // 指针数组是一个数组,其元素都是指针。 int a = 100, b = 200, c = 300, d = 400; int *arr_of_ptrs[4] = {&a, &b, &c, &d}; printf(\"------------指针数组示例:------------\\n\"); for (int i = 0; i < 4; i++) { printf(\"arr_of_ptrs[%d] = %p, *arr_of_ptrs[%d] = %d\\n\", i, (void *)arr_of_ptrs[i], i, *arr_of_ptrs[i]); } // 2. 数组指针 (Pointer to Array) // 数组指针是一个指针,它指向整个数组。 int arr[4] = {10, 20, 30, 40}; // 声明一个数组指针:指向包含4个整数的数组 int (*arr_ptr)[4] = &arr; printf(\"\\n------------数组指针示例:------------\\n\"); printf(\"arr_ptr地址: %p\\n\", (void *)arr_ptr); printf(\"arr地址: %p\\n\", (void *)arr); // 通过数组指针访问数组元素 printf(\"第一个元素: %d\\n\", (*arr_ptr)[0]); printf(\"第二个元素: %d\\n\", (*arr_ptr)[1]); // 指针算术:移动整个数组的大小 printf(\"arr_ptr + 1地址: %p (前进%d字节)\\n\", (void *)(arr_ptr + 1), (int)((char *)(arr_ptr + 1) - (char *)arr_ptr)); return 0;}
int (*p_array)[4] = &arr;
与 int *p = arr;
的区别
这两种指针声明方式在C语言中有本质的区别,主要体现在指针类型、语义和指针算术运算上。
代码示例
#include int main() { int arr[4] = {10, 20, 30, 40}; // 方式1: 指向数组第一个元素的指针 int *p = arr; // 方式2: 指向整个数组的指针 int (*p_array)[4] = &arr; printf(\"数组地址: %p\\n\", (void *)arr); printf(\"&arr地址: %p\\n\", (void *)&arr); printf(\"\\nint *p = arr:\\n\"); printf(\"p地址: %p, 值: %d\\n\", (void *)p, *p); printf(\"p+1地址: %p, 值: %d\\n\", (void *)(p+1), *(p+1)); printf(\"\\nint (*p_array)[4] = &arr:\\n\"); printf(\"p_array地址: %p\\n\", (void *)p_array); printf(\"(*p_array)[0] = %d\\n\", (*p_array)[0]); printf(\"p_array+1地址: %p\\n\", (void *)(p_array+1)); return 0;}
主要区别
1. 指针类型不同
-
int *p = arr;
:p
是指向整型的指针(int*
)- 指向数组的第一个元素
-
int (*p_array)[4] = &arr;
:p_array
是指向包含4个整数的数组的指针(int(*)[4]
)- 指向整个数组
2. 指针算术运算不同
-
int *p = arr;
:p + 1
前进一个int
的大小(通常4字节)- 指向数组的下一个元素
-
int (*p_array)[4] = &arr;
:p_array + 1
前进整个数组的大小(4 × sizeof(int) = 16字节)- 指向下一个相同大小的数组
3. 解引用方式不同
-
int *p = arr;
:*p
直接得到数组的第一个元素的值p[i]
或*(p+i)
访问数组的第i个元素
-
int (*p_array)[4] = &arr;
:*p_array
得到整个数组(类型为int[4]
)(*p_array)[i]
访问数组的第i个元素
内存布局示意图
内存地址: 0x1000 0x1004 0x1008 0x100C值: 10 20 30 40 ↑ ↑ p p+1 ↑ p_array (指向整个数组) ↑ p_array+1 (指向下一个数组,地址0x1010)
实际应用场景
使用 int *p = arr;
(常见用法)
// 遍历数组元素int arr[4] = {10, 20, 30, 40};int *p = arr;for (int i = 0; i < 4; i++) { printf(\"%d \", *(p + i)); // 或 printf(\"%d \", p[i]);}
使用 int (*p_array)[4] = &arr;
(特殊用法)
// 处理二维数组int matrix[3][4] = { {1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};// 指向二维数组的指针int (*p_matrix)[4] = matrix;for (int i = 0; i < 3; i++) { for (int j = 0; j < 4; j++) { printf(\"%d \", p_matrix[i][j]); // 或 printf(\"%d \", (*(p_matrix + i))[j]); } printf(\"\\n\");}
类型兼容性
需要注意的是,虽然 arr
和 &arr
的值相同(都指向数组的起始地址),但它们的类型不同:
arr
的类型是int[4]
,在大多数表达式中退化为int*
&arr
的类型是int(*)[4]
因此,以下赋值需要类型转换:
int arr[4] = {10, 20, 30, 40};int *p1 = arr; // 正确,类型兼容int *p2 = (int *)&arr; // 需要显式类型转换
总结
int *p = arr;
创建了一个指向数组第一个元素的指针,适用于大多数数组操作int (*p_array)[4] = &arr;
创建了一个指向整个数组的指针,主要用于处理多维数组- 两种指针的值相同(指向同一地址),但类型不同,导致指针算术运算的行为不同
- 理解这一区别有助于编写更准确和高效的C代码,特别是在处理多维数组时