在形式参数中省略二维数组的第二维不会引发任何错误或警告

问题描述

我正在仔细研究此问题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允许这种声明?
如果可以肯定会在使用指针时抛出错误,那么为什么在声明自身时却不抛出错误呢?为什么要等待使用指针引发错误
允许这样的声明有什么具体原因吗?

解决方法

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

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

p的类型是“指向未知数量int的数组的指针。由于数组中元素的数量未知,因此类型不完整。因此,不允许添加。

有趣的是,即使(*p)[1]指的是同一事物,也可以使用p[0][1]。因为计算*p不需要指针加法,所以可以使用。 p指向一个数组,因此即使我们不知道数组的大小,我们也知道该数组的起始位置。

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

,

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

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

那又如何呢?您正在询问有关...中的参数p的声明>

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

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

为什么C允许这种声明?

为什么不呢?我的意思是,不完整的类型有些怪异,但它们可以达到有用的目的。您提供的参数声明与C的要求一致。

如果可以肯定会在使用指针时抛出错误,那么为什么在声明自身时不抛出错误呢?为什么要等待使用指针引发错误?

因为仅某些指针使用是错误的。例如,您可以将其转换为整数或其他指针类型,或将其分配给兼容类型的变量。实际上,尽管C并未定义对其他类型不完整类型的指针进行反引用的行为,但它确实允许您对不完整的 array 类型的指针进行解引用。

是否有允许这种声明的特定原因?

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