我记得有一个例子演示了指针和数组之间的区别。
当作为函数参数传递时,数组衰减为指向数组中第一个元素的指针,但它们并不等效,如下所示:
//file file1.c
int a[2] = {800, 801};
int b[2] = {100, 101};
//file file2.c
extern int a[2];
// here b is declared as pointer,
// although the external unit defines it as an array
extern int *b;
int main() {
int x1, x2;
x1 = a[1]; // ok
x2 = b[1]; // crash at runtime
return 0;
}
链接器不会对外部变量进行类型检查,因此在编译时不会产生错误。问题是 b
实际上是一个数组,但是编译单元 file2
并不知道这一点并将 b
视为指针,导致尝试取消引用时发生崩溃。
我记得当时有人对此进行解释时它非常有道理,但现在我不记得解释了,也无法自己想出来。
所以我想问题是在访问元素时数组与指针的处理方式有何不同? (因为我认为 p[1]
被转换为(汇编等价物)*(p + 1)
而不管 p
是否是一个数组或指针——我显然错了)。
两次解引用生成的程序集(VS 2013):
注意:1158000h
和1158008h
分别是a
和b
的内存地址
12: x1 = a[1];
0115139E mov eax,4
011513A3 shl eax,0
011513A6 mov ecx,dword ptr [eax+1158000h]
011513AC mov dword ptr [x1],ecx
13: x2 = b[1];
011513AF mov eax,4
011513B4 shl eax,0
011513B7 mov ecx,dword ptr ds:[1158008h]
011513BD mov edx,dword ptr [ecx+eax]
011513C0 mov dword ptr [x2],edx
最佳答案
感谢@tesseract 在评论中提供的链接:Expert C Programming: Deep C Secrets (第 96 页),我想出了一个简单的答案(书中解释的简单简化版本;要获得完整的学术答案,请阅读本书):
- 声明
int a[2]
时:- 编译器为
a
提供了一个存储该变量的地址。这个地址也是数组的地址,因为变量的类型是数组。 - 访问
a[1]
意味着:- 检索该地址,
- 添加偏移量和
- 访问这个计算出的新地址的内存。
- 编译器为
- 声明
int *b
时:- 编译器也有一个
b
的地址,但这是指针变量的地址,而不是数组。 - 因此访问
b[1]
意味着:- 检索该地址,
- 访问该位置以获得
b
的值,即数组的地址 - 给这个地址加上一个偏移量然后
- 访问最终的内存位置。
- 编译器也有一个
关于c - 取消引用指针和访问数组元素之间的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21972465/