为什么arr和& arr一样?

时间:2012-01-18 20:04:54

标签: c++ c pointers

我已经编程了很多年的c / c ++,但今天的意外发现让我有点好奇......为什么两个输出在下面的代码中产生相同的结果? (arr当然是arr[0]的地址,即指向arr[0]的指针。我原本期望&arr成为该指针的地址,但它具有相同的地址值为arr

  int arr[3];
  cout << arr << endl;
  cout << &arr << endl;

备注:这个问题已经结束,但现在又被打开了。 (谢谢?)

我知道&arr[0]arr评估的数字相同,但不是我的问题!问题是为什么&arrarr评估的数字相同。如果arr是文字(不存储任何软件),那么编译器应该抱怨并说arr不是左值。如果arr的地址存储在某处,那么&arr应该会为我提供该位置的地址。 (但事实并非如此)

如果我写

  

const int * arr2 = arr;

然后arr2[i]==arr[i]表示任何整数i,但&arr2 != arr

6 个答案:

答案 0 :(得分:17)

#include <cassert>

struct foo {
    int x;
    int y;
};

int main() {    
    foo f;
    void* a = &f.x;
    void* b = &f;
    assert(a == b);
}

出于同样的原因,两个地址ab高于are the same。对象的地址与其第一个成员的地址相同(但它们的类型不同)。

                            arr
                      _______^_______
                     /               \
                    | [0]   [1]   [2] |
--------------------+-----+-----+-----+--------------------------
      some memory   |     |     |     |        more memory
--------------------+-----+-----+-----+--------------------------
                    ^
                    |
           the pointers point here

正如您在此图中所看到的,数组的第一个元素与数组本身位于同一地址。

答案 1 :(得分:13)

他们不一样。他们只是在同一个记忆位置。例如,您可以写arr+2来获取arr[2]的地址,而不是(&arr)+2来执行相同的操作。

此外,sizeof arrsizeof &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)

它们不一样。

更严格的解释:

arrint [3]类型的左值。试图使用 像arr这样的表达式中的cout << arr将导致左值到右值的转换,因为没有数组类型的右值,它会将它转换为类型int *的右值并且使用值等于&arr[0]。这是你可以展示的。

&arrint (*)[3]类型的右值,指向数组对象本身。这里没有魔法:-)这个指针指向与&arr[0]相同的地址,因为数组对象及其第一个成员在内存中的完全相同的位置开始。这就是打印时得到相同结果的原因。


确认它们不同的一种简单方法是比较*(arr)*(&arr):第一个是int类型的左值,第二个是类型{{1}的左值}。

答案 5 :(得分:2)

指针和数组通常可以相同地处理,但存在差异。指针确实有一个内存位置,因此您可以获取指针的地址。但是在运行时,数组没有指向它。因此,对于编译器,获取数组的地址在语法上定义为与第一个元素的地址相同。这是有道理的,大声朗读这句话。