繁体   English   中英

为什么arr和&arr一样?

[英]Why is arr and &arr the same?

我已经编程了很多年的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;

那么对于任何整数iarr2[i]==arr[i] ,但是&arr2 != arr

#include <cassert>

struct foo {
    int x;
    int y;
};

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

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

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

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

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

另外, sizeof arrsizeof &arr是不同的。

两者具有相同的值但不同的类型。

当它自己使用时(不是&sizeof的操作数), arr求值为指向int的指针,该指针保存数组中第一个int的地址。 &arr计算指向三个int的数组的指针,保存数组的地址。 由于数组中的第一个int位于数组的最开头,因此这些地址必须相等。

如果你对结果进行一些数学运算,两者之间的差异就会变得明显:

arr+1将等于arr + sizeof(int)

((&arr) + 1)将等于arr + sizeof(arr) == arr + sizeof(int) * 3

编辑:至于如何/为什么会发生这种情况,答案很简单:因为标准是这样说的。 特别是,它说(§6.3.2.1/ 3):

除非它是sizeof运算符或一元&运算符的操作数,或者是用于初始化数组的字符串文字,否则将类型为''array of type''的表达式转换为类型为''指针的表达式type''指向数组对象的初始元素,而不是左值。

[注意:这个特别引用来自C99标准,但我相信在C和C ++标准的所有版本中都有相同的语言]。

在第一种情况下( arr本身), arr不被用作sizeof,unary等的操作数,因此它被转换(不提升)到类型“指向类型的指针”(在这种情况下,“指针”)到int“)。

在第二种情况下( &arr ),名称显然用作一元的操作数&操作员-使得转换不会发生。

地址相同但两个表达式都不同。 它们只是从相同的内存位置开始。 两种表达的类型都不同。

arr的值的类型为int * ,而&arr的值的类型为int (*)[3]

&是地址运算符,对象的地址是指向该对象的指针。 指向int [3]类型的对象的指针的类型为int (*)[3]

她们不一样。

更严格的解释:

arrint [3]类型的左值 int [3] 使用的尝试arr在像一些表达式cout << arr将导致左值到右值转换其中,因为不存在阵列型的右值,将其转换为式的一个右值int *和具有等于值&arr[0] 这是你可以显示的。

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


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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM