【问题标题】:Ommiting second dimension for 2-d array in formal argument doesn't throw any error or warning在形式参数中省略二维数组的第二维不会引发任何错误或警告
【发布时间】:2020-08-28 02:08:57
【问题描述】:

我正在查看这个问题Why is it allowed to omit the first dimension, but not the other dimensions when declaring a multi-dimensonal array? 的答案以及其他一些问题,我知道我们可以省略第一个维度,但其他维度是不可避免的。
令我惊讶的是,以下代码执行得非常好:

#include<stdio.h>
void f1(int (*p)[]){
    //SOMETHING
}
int main()
{
    int a[3][3]={1,2,3,4,5,6,7,8,9};
    f1(a);
}

但是,如果我使用指针 p 打印一些值,例如

printf("%d",p[0][1]);

它给出了一条错误消息:

error: invalid use of array with unspecified bounds

为什么 C 允许这样的声明?
如果非常确定它会在使用指针时抛出错误,那么为什么它在声明本身时不抛出错误?为什么要等待指针使用抛出错误?
允许这样的声明有什么具体原因吗?

【问题讨论】:

    标签: c pointers multidimensional-array pointer-to-array


    【解决方案1】:

    表达式p[0][1] 包含p[0]p[0] 被定义为等同于 *(p+0)。这使用了一个指针和一个整数的相加。

    有一个规则,用指针加法需要一个指向完整对象类型的指针。这是因为计算地址必须更改的字节数通常需要知道所指向对象的大小。加零的时候不会,但是这个规则中没有例外。

    p 的类型是“指向未知数 int 的数组的指针。因为数组中的元素个数未知,所以类型不完整。所以不允许添加。

    有趣的是,(*p)[1] 是允许的,即使它指的是同一事物 p[0][1] 会。这是允许的,因为计算*p 不需要添加指针。 p 指向一个数组,因此我们知道该数组从哪里开始,即使我们不知道它的大小。

    需要知道对象大小才能进行指针运算,这就是为什么数组的元素必须具有完整类型的原因(因此,如果这些元素本身是数组,则必须给出它们的长度,以使它们完整,因此所有内部维度的数组必须是已知的)。但是指针可以指向不完整的类型,所以当指针指向数组时,不需要知道数组的维数。

    【讨论】:

      【解决方案2】:

      我知道我们可以省略第一个维度,但不可避免地要指定其他维度。

      是的。声明数组时,元素类型必须是完整类型。这是标准第 6.7.6.2/1 段中指定的正式约束,因此符合标准的编译器必须诊断违规。

      但那又怎样?你问的是参数p在...中的声明

      void f1(int (*p)[]){
      

      ... 具有 pointer 类型。具体来说,它是一个指向未知数量整数数组的指针。该数组类型仅省略第一个维度,如您所知,这是允许的,尽管它使该类型不完整。允许指向不完整类型的指针(它们本身就是完整类型),void * 类型是典型的子类型。此外,int(*)[] 类型与您传递的参数类型兼容,即int(*)[3](不是int[3][3])。

      为什么 C 允许这样的声明?

      为什么不应该呢?我的意思是,不完整的类型有点奇怪,但它们有一个有用的目的。您提供的参数声明符合C的要求。

      如果非常确定它会在使用指针时抛出错误,那么为什么它在声明本身时不抛出错误?为什么要等待指针使用抛出错误?

      因为只有指针的某些用途是错误的。例如,您可以将其转换为整数或其他指针类型,或将其分配给兼容类型的变量。事实上,虽然 C 没有定义解引用指向其他不完整类型的指针的行为,但它确实允许你解引用指向不完整 array 类型的指针。

      允许这样的声明有什么具体原因吗?

      一致性?用处?您的问题似乎基于这样一种信念,即允许它一致、无用或两者兼而有之,但两者都不是。 C 有一个不完整类型的概念。它允许指向不完整类型的指针,这对语言非常重要,并且在这方面它不区分不完整类型。 C 也没有针对指向不完整类型的指针作为函数参数的类型制定特殊情况规则。

      【讨论】:

      • 这也是一个很好的方法。我还考虑过解释第一个维度被省略的原因的 6.3.2.1 数组/指针转换方面。如果剩余的维度被省略,那么您将讨论指向不完整类型@Eric 的指针。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-07-30
      • 2021-05-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-26
      相关资源
      最近更新 更多