为什么我们不能将数组的地址分配给指针?

Why can't we assign address of array to pointer?

int q[10]={0};
cout << q << endl;
cout << &q << endl;
cout << &q[0] << endl;

输出是

0x7fffd4d2f860 
0x7fffd4d2f860 
0x7fffd4d2f860 

现在当我这样做时->

int *r=q;    // allowed
int *r=&q[0] // allowed
int *r=&q    // not allowed

为什么第三个赋值本质上是一样的却不允许?

您不能进行第三次赋值,因为 &q 的类型是 int (*)[10],与 int* r 的类型不兼容。

cout << &q 的输出不显示 &q 的类型。请参阅 this 文档 link。

Why is the third assignment not allowed when it is essentially the same thing?

因为C++语言有个特性叫做"type safety"。有一个类型系统可以帮助您保持程序逻辑的合理性。

一个特殊的规则是任意指针类型不能用于初始化其他不兼容类型的指针。在这种情况下,您有一个指向 int 类型的指针(即 int*),您尝试使用指向 10 int 类型数组(即 int(*)[10])的类型指针表达式对其进行初始化。一种类型不能隐式转换为另一种类型,因此程序格式错误。

Then why does cout print same things in all of the three cases?

因为所有的指针都具有相同的值。数组第一个元素的第一个字节与整个数组的第一个字节相同

恰好流插入运算符对所有指针类型的处理1完全相同,因此具有相同值但不同类型的指针产生相同的输出。

1 指向字符类型的指针是一个例外。他们的待遇完全不同。


Why can't we assign address of array to pointer?

其实我们可以把一个数组的地址赋给一个指针。我们只是不能将数组(或与此相关的任何其他对象)的地址分配给错误类型的指针。在这种情况下,我们需要一个指向数组的指针:

int (*r)[10] = &q;

如果你有一个像

这样声明的数组
T a[N];

其中 T 是某种类型说明符,然后指向数组的指针将被声明为

T ( *p )[N] = &a;

一般规则如下。如果你有一个多维数组(包括一维数组),例如

T a[N1][N2][N3];

然后你可以像这样重写这个声明

T ( a[N1] )[N2][N3];

要获取指向数组第一个元素的指针,只需按以下方式替换括号中的内容

T ( *p )[N2][N3] = a;

如果你想得到一个指向整个数组的指针,那么像这样重写数组的声明

T ( a )[N1][N2][N3];

并进行替换

T ( *p )[N1][N2][N3] = &a;

将此与标量对象的声明和指向它的指针进行比较。

例如

T obj;

您可以像这样重写声明

T ( obj );

现在获取指向您可以写入的对象的指针

T ( *p ) = &obj;

当然在这种情况下括号是多余的,上面的声明等同于

T *p = &obj;

至于这段代码

int q[10]={0};
cout << q << endl;
cout << &q << endl;
cout << &q[0] << endl;

及其输出

0x7fffd4d2f860 
0x7fffd4d2f860 
0x7fffd4d2f860 

然后表达式中使用的数组指示符将被转换为指向其第一个元素的指针。

所以实际上这些语句中的两个表达式q&q[0]

cout << q << endl;
cout << &q[0] << endl;

是等价的。另一方面,数组本身的地址是数组占用的内存范围的地址。在范围的开头是数组的第一个元素。所以三个表达式给出相同的结果:数组占用的内存范围的地址。

q是定长数组。在表达式 decays 中将 q 本身指定为指向 q 的第一个元素的指针。因此,q 衰减 到与 &q[0] returns 相同的指针值。 &q,另一方面,returns q 变量本身的内存地址,对于数组,它的第一个元素占用相同的内存地址。

std::ostream定义了一个operator<<(void*)void*可以接受(几乎)任何类型的指针。由于所有三个 cout 调用都解析到相同的内存地址,并且有一个 operator<< 接受所有三种类型的指针,这就是为什么所有三个调用打印相同的数字。

关于您的作业:

  • q 是一个 int[10],它 衰减 成一个 int*,这就是为什么 int *r=q; 有效。

  • &q[0] 取消引用 q 以访问其第一个元素,即 int,然后获取该元素的地址,生成 int*,这就是 int *r=&q[0]; 起作用的原因。

  • 因为 q 是一个 int[10]&q 是一个 int(*)[10],它不会 衰减 变成 int*,这就是 int *r=&q; 不起作用的原因。您必须使用正确的类型声明 r

    int (*r)[10] = &q;