C语言指针数组与多元素内存指针的访问差异问题
二者底层核心差异
你的认知偏差首先来自对两个对象类型的误判,二者存储的内容、内存结构完全不同:
int *obj1[N];是标准的指针数组:本质是长度为N的数组,内存直接在栈/静态存储区分配,总大小为N * sizeof(int*)。数组的每个元素都是int*类型(指向int的指针),每个元素可以独立指向任意位置的int变量,不需要保证指向的int变量内存连续。- 你实现的
int *obj2; obj2 = malloc(N*sizeof(int))本质是单级int指针:obj2本身是一个仅占一个指针宽度的变量,指向堆上申请的连续内存块的首地址。你申请的内存块总大小为N * sizeof(int),每个内存槽位存储的是int类型的整数值,不是指针。
访问写法差异的根本原因
C语言中下标运算符[]的语义是固定的:a[i] 100%等价于*(a + i),差异完全来自两个对象的类型不同,结合运算符优先级([]优先级高于单目*)就能完全解释:
- 对
obj1来说:obj1作为数组名,在表达式中会退化为指向数组首元素的指针,首元素类型是int*,因此obj1[i]取到的是数组第i个元素,类型仍然是int*(一个内存地址)。要拿到这个地址存储的实际int值,必须额外做一次解引用,也就是*obj1[i](等价于*(obj1[i]))。 - 对你当前实现的
obj2来说:obj2本身是int*类型,指向堆上int数组的首元素,因此obj2[i]等价于*(obj2 + i),直接取到的就是第i个槽位存储的int值,自然不需要额外解引用。
如果你真的要让
obj2实现和obj1一样存储一组int指针的效果,需要修改为二级指针写法,此时访问逻辑就和obj1完全一致:// 指向int*类型的指针,用来存指针数组的首地址 int **obj2; // 申请N个int*大小的堆内存,每个槽位存int指针 obj2 = malloc(N * sizeof(int*)); // 此时访问第i个指针指向的值,同样需要解引用 val = *obj2[i];
内存结构直观对比
以64位系统、N=2为例:
- obj1的内存布局:
栈区连续16字节(2个8字节指针):
+0偏移:存第一个int指针,比如0x7fff00(指向其他位置的int值123)
+8偏移:存第二个int指针,比如0x7fff08(指向其他位置的int值456)
两个指针指向的int值不需要连续,obj1[0]拿到的是地址0x7fff00,必须解引用才能拿到123。 - 你当前实现的obj2的内存布局:
栈区8字节存obj2本身的值,也就是堆内存首地址0x123400;
堆区连续8字节(2个4字节int):
+0偏移:直接存int值123
+4偏移:直接存int值456obj2[0]直接偏移计算后解引用拿到123,不需要额外操作。
内容的提问来源于stack exchange,提问作者hijit
相关产品推荐
相关产品推荐

