实现这样的二维数组时:
int a[3][3];
这些持有:A=&A[0]
,同时A[0]=&A[0][0]
。所以,A=&(&A[0][0])
,基本上说A
是数组第一个元素地址的地址,这不是真的。这里我的错误是什么? A
真的会衰减到指针的指针吗?
答案 0 :(得分:1)
您的错误在于您对数组和指针之间的关系有不正确的理解。数组不是指针。这是一个数组。但是,数组 可以隐式转换为指向其自己的第一个元素的指针。所以,虽然这个表达式确实评估为true:
A == &A[0]
说A
&A[0]
是不正确的。转换不会在所有表达式中发生。例如:
&A
这不会取A
的第一个元素的地址(甚至没有意义)。它需要A
的实际地址,其类型为int[3][3]
。所以&A
的类型是int(*)[3][3]
,读作“指向3个3个数组的数组的指针”。
&A
和&A[0]
之间的主要区别在于,如果您向&A
添加1,您将获得3 * 3 * sizeof(int)
字节之外的地址,而如果您添加1到&A[0]
,你会得到一个只有3 * sizeof(int)
字节的指针。
考虑到这一切,你应该能够看到你的错误所在。 A[0]
不 &A[0][0]
,但它可以隐式转换为它。但是,与所有转换一样,这会产生一个临时的,您无法获取该地址。所以表达式&(&A[0][0])
甚至没有意义。
答案 1 :(得分:0)
由于对我之前回答的反应,我做了一些研究,以便在我的解释中了解更多错误。 在这里找到了一个相当精细的主题解释:
http://eli.thegreenplace.net/2009/10/21/are-pointers-and-arrays-equivalent-in-c
我会试着总结一下:
如果您有以下内容:
char array_place[100] = "don't panic";
char* ptr_place = "don't panic";
在内存中表示它的方式完全不同。 而ptr_place是一个真正的指针,array_place只是一个标签。
char a = array_place[7];
char b = ptr_place[7];
C中数组的语义规定数组名是数组第一个元素的地址,这与说它是指针不同。因此在赋值给a,数组的第8个字符是通过将array_place的值偏移7来实现的,并将结果地址指向的内容移动到al寄存器中,然后移入a。
指针的语义完全不同。指针只是一个常规变量,碰巧将另一个变量的地址保存在里面。因此,为了实际计算字符串的第8个字符的偏移量,CPU将首先将指针的值复制到寄存器中,然后再将其递增。这需要另一条指令[1]。
实际上并没有破解编译器的程序员经常会忽略这一点。 C中的变量只是内存位置的方便的字母数字假名。如果我们编写汇编代码,我们只需在某个内存位置创建一个标签,然后访问此标签,而不是始终对内存值进行硬编码 - 这就是编译器的作用。
嗯,实际上由于加载和重定位问题,地址没有以绝对方式进行硬编码,但为了讨论起见,我们不必深入了解这些细节。
标签是编译器在编译时分配的东西。从这里可以看出数组和指针之间的巨大差异。 这也解释了为什么sizeof(array_place)给出了数组的完整大小,其中指针的大小将给出指针的大小。
我必须说,我自己并没有意识到这些微妙的差异,而且我在C和C ++以及数组中也已经编写了很长时间。
然而,如果数组元素的名称是数组的第一个元素的地址。您可以创建一个指针并将其初始化为该值
char* p = array_place
p将指向字符所在的内存位置。
总结:
必须牢记数组名称和指针之间的一个区别。指针是一个变量,因此p = array_place和p ++是合法的。但是数组名称不是变量;像array_place = p和array_place ++这样的结构是非法的。我知道的; - )