为什么arr和&arr一样?

rag*_*ius 21 c c++ pointers

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

  int arr[3];
  cout << arr << endl;
  cout << &arr << endl;
Run Code Online (Sandbox Code Playgroud)

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

我知道&arr[0]arr评估相同的数字,但这不是我的问题!问题是为什么&arrarr评估相同的数字.如果arr是文字(不存储任何软件),那么编译器应该抱怨并说这arr不是左值.如果地址arr存储在某个地方,那么&arr应该给我该地点的地址.(但这种情况并非如此)

如果我写

const int*arr2 = arr;

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

R. *_*des 17

#include <cassert>

struct foo {
    int x;
    int y;
};

int main() {    
    foo f;
    void* a = &f.x;
    void* b = &f;
    assert(a == b);
}
Run Code Online (Sandbox Code Playgroud)

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

                            arr
                      _______^_______
                     /               \
                    | [0]   [1]   [2] |
--------------------+-----+-----+-----+--------------------------
      some memory   |     |     |     |        more memory
--------------------+-----+-----+-----+--------------------------
                    ^
                    |
           the pointers point here
Run Code Online (Sandbox Code Playgroud)

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


Mr *_*ter 13

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

另外,sizeof arrsizeof &arr不同.

  • @Mooing:这是错误的,`int(*)[3]`是*不*可转换为`int**`.指向数组的指针需要内部维度的确切大小才能知道步骤的距离:http://ideone.com/iDkB7. (5认同)
  • 值得注意的是,`(&arr)+ 2`将编译,甚至可能运行,但它是未定义的行为,并且_not_将给你'arr [2]`. (4认同)

Jer*_*fin 6

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

当它本身使用时(不是&或的操作数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),名称显然被用作一元的操作数&操作员-使得转换并没有发生.


oua*_*uah 5

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

的值arr是类型的int *和的值&arr是类型的int (*)[3].

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