我正在研究这个问题的答案为什么在声明多维数组时允许省略第一个维度,而不允许省略其他维度?以及其他一些问题,我理解我们可以省略第一个维度,但其他维度不可避免地会被指定
令我惊讶的是,以下代码执行得非常好:
#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]
。CCD_ 4被定义为等效于CCD_。这使用一个指针和一个整数的加法。
有一条规则是,添加指针需要一个指向完整对象类型的指针。这是因为计算地址必须更改的字节数通常需要知道所指向对象的大小。在添加零时不会这样做,但规则中没有例外。
p
的类型是"指向未知数量的int
的数组的指针。因为数组中的元素数量未知,所以类型不完整。因此不允许添加。
有趣的是,(*p)[1]
是允许的,尽管它指的是p[0][1]
所指的相同内容。这是允许的,因为计算*p
不需要添加指针。p
指向一个数组,所以我们知道该数组从哪里开始,尽管我们不知道它的大小。
指针算术需要知道对象大小,这就是为什么数组的元素必须具有完整的类型(因此,如果这些元素本身就是数组,则必须给定它们的长度,以使它们完整,因此数组的所有内部维度都必须已知(。但是允许指针指向不完整的类型,因此,当指针指向数组时,不需要知道数组维度。
我知道我们可以省略第一个维度,但不可避免地要指定其他维度。
是。声明数组时,元素类型必须是完整类型。这是本标准第6.7.6.2/1段中规定的形式约束,因此符合要求的编译器必须诊断违规行为。
但那又怎样?您正在询问中参数p
的声明。。。
void f1(int (*p)[]){
。。。其具有指针类型。具体来说,它是一个指向未知整数数组的指针。该数组类型只省略了第一个维度,正如您所知,这是允许的,尽管它使该类型成为不完整的类型。允许指向不完整类型的指针(它们本身就是完整类型(,类型void *
是典型的子类型。此外,类型int(*)[]
与您正在传递的参数的类型兼容,即int(*)[3]
(而不是int[3][3]
(。
为什么C允许这样的声明?
为什么不应该?我的意思是,不完整的类型有点奇怪,但它们有一个有用的目的。您提供的参数声明与C的要求一致。
如果非常确定它将在指针的使用中抛出错误,那么为什么它不在声明时抛出错误呢?为什么要等待指针的使用来抛出错误?
因为只有指针的某些使用是错误的。例如,您可以将其转换为整数或其他指针类型,或者将其分配给兼容类型的变量。事实上,尽管C没有定义将指针取消引用到其他类型的不完整类型的行为,但它确实允许您取消引用不完整数组类型的指针。
允许这样的声明有什么具体的原因吗?
一致性?有用吗?你的问题似乎是基于这样一种信念,即允许它在中是一致的、无用的,或者两者兼而有之,但两者都不是。C有一个不完全类型的概念。它允许指向不完全类型的指针,这对语言非常重要,并且在这方面不区分不完全类型。C也没有针对指向函数参数类型的不完整类型的指针制定特殊情况规则。