指针数组与数组指针的区别
#include <stdio.h>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 <stdio.h>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代码,特别是在处理多维数组时