我已经编程了很多年的c / c ++,但今天的意外发现让我有点好奇......为什么两个输出在下面的代码中产生相同的结果? (arr
当然是arr[0]
的地址,即指向arr[0]
的指针。我原本期望&arr
成为该指针的地址,但它具有相同的地址值为arr
)
int arr[3];
cout << arr << endl;
cout << &arr << endl;
备注:这个问题已经结束,但现在又被打开了。 (谢谢?)
我知道&arr[0]
和arr
评估的数字相同,但不是我的问题!问题是为什么&arr
和arr
评估的数字相同。如果arr
是文字(不存储任何软件),那么编译器应该抱怨并说arr
不是左值。如果arr
的地址存储在某处,那么&arr
应该会为我提供该位置的地址。 (但事实并非如此)
如果我写
const int * arr2 = arr;
然后arr2[i]==arr[i]
表示任何整数i
,但&arr2 != arr
。
答案 0 :(得分:17)
#include <cassert>
struct foo {
int x;
int y;
};
int main() {
foo f;
void* a = &f.x;
void* b = &f;
assert(a == b);
}
出于同样的原因,两个地址a
和b
高于are the same。对象的地址与其第一个成员的地址相同(但它们的类型不同)。
arr
_______^_______
/ \
| [0] [1] [2] |
--------------------+-----+-----+-----+--------------------------
some memory | | | | more memory
--------------------+-----+-----+-----+--------------------------
^
|
the pointers point here
正如您在此图中所看到的,数组的第一个元素与数组本身位于同一地址。
答案 1 :(得分:13)
他们不一样。他们只是在同一个记忆位置。例如,您可以写arr+2
来获取arr[2]
的地址,而不是(&arr)+2
来执行相同的操作。
此外,sizeof arr
和sizeof &arr
不同。
答案 2 :(得分:6)
两者具有相同的价值但不同的类型。
当它本身使用时(不是&
或sizeof
的操作数),arr
计算指向int
的指针,保存第一个{{1}的地址在数组中。
int
计算指向三个&arr
的数组的指针,保存数组的地址。由于数组中的第一个int
必须位于数组的最开头,因此地址必须相等。
如果对结果进行一些数学运算,两者之间的差异就会变得明显:
int
将等于arr+1
。
arr + sizeof(int)
将等于((&arr) + 1)
== arr + sizeof(arr)
编辑:至于如何/为何发生这种情况,答案很简单:因为标准是这样说的。特别是,它说(§6.3.2.1/ 3):
除非它是sizeof运算符或一元&amp;的操作数。运营商,或者是 用于初始化数组的字符串文字,具有类型''数组类型''的表达式将转换为类型为''指向类型'的指针的表达式,指向数组对象的初始元素而不是左值。
[注意:这个特别引用来自C99标准,但我相信在C和C ++标准的所有版本中都有相同的语言]。
在第一种情况下(arr + sizeof(int) * 3
本身),arr
未被用作sizeof,unary&amp;等的操作数,因此它被转换(不提升)为该类型“指向类型的指针”(在本例中,“指向int的指针”)。
在第二种情况下(arr
),显然的名称被用作一元&arr
运算符的操作数 - 因此转换不发生。
答案 3 :(得分:5)
地址相同但两个表达式都不同。它们只是从相同的内存位置开始。两种表达的类型都不同。
arr
的值为int *
,&arr
的值为int (*)[3]
。
&
是地址运算符,对象的地址是指向该对象的指针。指向int [3]
类型对象的指针属于int (*)[3]
答案 4 :(得分:4)
它们不一样。
更严格的解释:
arr
是int [3]
类型的左值。试图使用
像arr
这样的表达式中的cout << arr
将导致左值到右值的转换,因为没有数组类型的右值,它会将它转换为类型int *
的右值并且使用值等于&arr[0]
。这是你可以展示的。
&arr
是int (*)[3]
类型的右值,指向数组对象本身。这里没有魔法:-)这个指针指向与&arr[0]
相同的地址,因为数组对象及其第一个成员在内存中的完全相同的位置开始。这就是打印时得到相同结果的原因。
确认它们不同的一种简单方法是比较*(arr)
和*(&arr)
:第一个是int
类型的左值,第二个是类型{{1}的左值}。
答案 5 :(得分:2)
指针和数组通常可以相同地处理,但存在差异。指针确实有一个内存位置,因此您可以获取指针的地址。但是在运行时,数组没有指向它。因此,对于编译器,获取数组的地址在语法上定义为与第一个元素的地址相同。这是有道理的,大声朗读这句话。