为什么不能将指向整型数组的指针赋值给指向整型的指针?

3
在C Primer Plus中,它告诉我一些遵循的赋值规则: 一个指向整型数组的指针不能赋值给一个指向整型的指针。
 int *pt; int a[3][2];
 pt=a; /* invalid */

一个指向包含两个整数的数组的指针不能赋值给一个指向包含三个整数的数组的指针。

 int (*pt)[3]; int a[3][2];
 pt=a; /* invalid */

老实说,我对这个解释感到困惑。因为尽管上面的指针是指向不同对象的指针,在内存中,指针都以无符号十六进制地址存储,这意味着它们具有相同的存储形式。它们在8位(64位操作系统)或4位(32位操作系统)中都是统一的。那么为什么它们不能在根本原因上互相分配呢?因为编译器禁止这种赋值方式吗?

3个回答

4
语言拥有类型的主要原因是为了帮助程序员避免错误。指向不同类型的事物的指针本身被视为不同类型。这样的规则可以捕捉到许多程序员可能将指针分配给错误事物的错误。
例如,一个整数、一个两个整数的数组和一个三个整数的数组是不同类型的事物,因此它们的指针是不同类型的指针,C语言的规则要求编译器在尝试分配一个指针给另一个时进行诊断。(可以通过使用强制类型转换来覆盖此行为,但在学习有关使用不同类型别名对象的C语言规则之前应该避免这样做。)
最简单的方法是,要将int *pt设置为指向int a[3][2]的第一个元素,则可以使用pt = &a[0][0];pt = a[0];。在后者中,由于a是三个包含两个int数组的数组,所以a[0]是一个包含两个int的数组。当在表达式中而非作为sizeof或一元&操作数时使用时,它会自动转换为指向其第一个元素的指针,因此它的行为与&a[0][0]相同。
顺便说一下,“...指针都以无符号的十六进制地址存储,这意味着它们具有相同的存储形式。它们在8位(64位操作系统)或4位(32位操作系统)中统一”这种说法通常不是正确的。C语言标准允许不同类型的指针具有不同的表示形式。虽然这在现代的C实现中很少见,但确实存在。
注释:用于初始化字符数组的字符串文本也不会被转换为指针。

1

对于指针来说,类型很重要,就像对于整数、浮点数、字符串等数据类型一样。指针算术运算是基于所指向的类型进行的。假设您有以下指针和对象:

int i;
int *pi = &i

int arr[10];
int (*pa)[10] = &arr;

如果表达式p的值为i的地址,则p + 1的值为i后面的下一个int对象的地址。同样地,如果pa的值为arr的地址,则pa + 1的值为arr后面的下一个10个元素的int数组的地址

这就是数组下标工作的方式 - 表达式a[i]被定义为*(a + i) - 给定起始地址a,从该地址偏移i个对象(而不是字节!),并解引用结果。

指向不同类型的指针本身是不同的类型,就像其他类型一样,它们不必具有相同的大小和表示:

6.2.5 类型
...
28 一个指向 void 的指针应该具有与字符类型指针相同的表示和对齐要求。48) 同样,指向兼容类型的限定或非限定版本的指针应具有相同的表示和对齐要求。所有结构类型的指针应该具有彼此相同的表示和对齐要求。所有联合类型的指针应该具有彼此相同的表示和对齐要求。其他类型的指针不需要具有相同的表示或对齐要求。
48) 相同的表示和对齐要求意味着可以作为函数的参数、函数的返回值以及联合体的成员进行交换。

C 2011 Online Draft

在大多数现代桌面和服务器系统(即:x86)上,指针类型的大小和表示方式都是相同的,但这是实现的功能,而不是语言本身。一个 int * 不必与 int (*)[3] 大小相同或具有相同的表示形式。
因此,除非它们是兼容类型,或其中一个是 void *,否则您不能将一种类型的指针分配给另一种类型的指针,除非您使用显式转换。
int *p = (int *) &arr;

0

指针变量int (*pt)[3]与数组int a[3][2]不兼容,但指针变量int (*pt)[2]与该数组兼容。

对于新的C程序员来说,声明int a[3][2];可能看起来像是声明a为长度为2的数组,其中每个元素都是长度为3的int数组,但在这种情况下,第一眼看起来会误导人。实际上,声明int a[3][2];a声明为长度为3的数组,其中每个元素都是长度为2的int数组。可以用伪英语按照声明中出现的顺序阅读它,维度以相同的顺序陈述,如“将a声明为长度为3的int数组的长度为2的数组”。在多维数组声明中,“内部”维度出现在“外部”维度的右侧。

声明 int (*p2)[2]; 可以用伪英语读作 "将 p2 声明为指向 int 数组[2] 的指针",当然,int (*p3)[3]; 可以读作 "将 p3 声明为指向 int 数组[3] 的指针"。指向不同长度的数组类型的指针类型彼此不兼容,因此 p2 的类型与 p3 的类型不兼容。
在表达式中(除了某些类型的表达式),多维数组衰减为指向其第一个元素的指针时,消失的是第一维(最左边或最外层的维度),所有剩余的维度(如果有)都保留在指向的类型中。例如,类型为 T [A][B][C] 的数组("数组[A]的数组[B]的数组[C]的T")会衰减为类型为 T (*)[B][C] 的指针("指向数组[B]的数组[C]的T的指针")。
在表达式p2 = a;p3 = a;中,a会衰减为&a[0],它的类型是int (*)[2]("指向int数组[2]的指针")。该指针类型与p2的类型兼容,但与p3的类型不兼容。赋值表达式p2 = a;是可以的,但赋值表达式p3 = a;涉及到不兼容指针类型之间的赋值。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接