【问题标题】:why can't a pointer-to-array-of-ints be assigned to a pointer-to-int?为什么不能将指向整数数组的指针分配给指向整数的指针?
【发布时间】:2020-03-16 13:43:47
【问题描述】:

在 c prime plus 中,它告诉我遵循了一些分配规则:

不能将指向整数数组的指针分配给指向整数的指针。

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

不能将指向二整数数组的指针分配给指向三整数数组的指针。

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

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

【问题讨论】:

    标签: c arrays pointers


    【解决方案1】:

    语言有类型的一个主要原因是帮助程序员避免犯错。指向不同类型事物的指针本身被视为不同类型。像这样的规则会捕捉到许多错误,程序员可能会将指针分配给错误的东西。

    一个int,一个两个int的数组,一个三个int的数组是不同类型的东西,所以指向它们的指针是不同类型的指针,C的规则需要编译器去诊断任何将一个分配给另一个的尝试。 (这可以通过使用强制转换来显式转换指针来覆盖,但在您了解有关使用不同类型的别名对象的 C 规则之前应该避免这种情况。)

    最简单的,设置int *pt指向int a[3][2]的第一个元素,你可以使用pt = &a[0][0];pt = a[0];。在后者中,由于a 是由两个int 组成的三个数组的数组,所以a[0] 是由两个int 组成的数组。当在表达式中使用不是sizeof 或一元&1 的操作数时,它会自动转换为指向其第一个元素的指针,因此它的行为与&a[0][0] 相同。

    顺便提一下,语句“…指针都以无符号的十六进制地址存储,这意味着它们具有相同的存储形式。它们统一为 8 位(64 位操作系统)或 4 位(32 位操作系统)”通常不正确。 C 标准允许不同类型的指针具有不同的表示形式。这在现代 C 实现中并不常见,但确实存在。

    脚注

    1 用于初始化字符数组的字符串文字也不会转换为指针。

    【讨论】:

      【解决方案2】:

      类型 matters 用于指针,就像它用于整数、浮点数、字符串等一样。指针运算是根据指向的类型完成的。假设您有以下指针和对象:

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

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

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

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

      6.2.5 类型
      ...
      28    指向 <strong>void</strong> 的指针应具有与 指向字符类型的指针。48) 同样,指向合格或不合格版本的指针 兼容类型应具有相同的表示和对齐要求。全部 指向结构类型的指针应具有相同的表示和对齐要求 作为彼此。所有指向联合类型的指针都应具有相同的表示形式和 对齐要求彼此。指向其他类型的指针不必相同 表示或对齐要求。
      48) 相同的表示和对齐要求意味着可互换性 函数的参数、函数的返回值以及联合的成员。

      C 2011 Online Draft

      在大多数现代桌面和服务器系统(阅读:x86)上,指针类型都具有相同的大小和表示,但这是实现的功能,而不是语言。 int * 不必与int (*)[3] 具有相同的大小或表示形式。

      因此,这就是为什么您不能将一种类型的指针分配给另一种类型的原因,除非它们是兼容的类型,或者其中之一是 void *,或者您使用显式转换:

      int *p = (int *) &arr;
      

      【讨论】:

        【解决方案3】:

        指针变量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 数组。它可以用伪英语阅读,其维度与它们在声明中出现的顺序相同,即“declare a as array[3] of array[2] of int”。在多维数组声明中,“内部”维度出现在“外部”维度的右侧。

        声明int (*p2)[2]; 可以用伪英语读作“declare p2 as pointer to array[2] of int”,当然int (*p3)[3]; 可以读作“ 将 p3 声明为指向 int 数组 [3] 的指针”。指向类型为不同长度的数组类型的指针类型相互不兼容,所以p2的类型与p3的类型不兼容。

        当在一个表达式(某些类型的表达式除外)中,多维数组衰减到指向其第一个元素的指针时,衰减过程中消除的是第一个维度(最左边或最外层的维度),并且所有剩余的维度(如果有的话)都保存在指向的类型中。例如,T [A][B][C] 类型的数组 ("array[A] of array[B] of array[C] of T") 将衰减为 T (*)[B][C] ("指向数组 [C] 的数组 [B] 的 T") 的指针。

        在表达式p2 = a;p3 = a; 中,a 衰减为&amp;a[0],其类型为int (*)[2](“指向整数数组[2] 的指针”)。该指针类型与p2 的指针类型兼容,但与p3 的指针类型不兼容。赋值表达式p2 = a; 是可以的,但是赋值表达式p3 = a; 涉及到不兼容的指针类型之间的赋值。

        【讨论】:

          猜你喜欢
          • 2017-02-12
          • 2012-05-16
          • 2011-04-02
          • 2019-10-27
          • 2012-01-24
          • 1970-01-01
          • 2012-01-23
          • 2011-12-16
          • 1970-01-01
          相关资源
          最近更新 更多