这样的声明没有初始化器
T a[][3];
(其中T 是某个类型说明符)声明了一个不完整类型的数组(数组的大小未知)。以这种方式声明的数组可能没有自动存储持续时间。但可以在文件范围内声明。在任何情况下,这样一个数组的元素类型(在上面的数组示例中元素类型是T[3])都应该是完整的。那就是你不能像例子那样声明一个数组
T a[][];
或
T a[3][];
这是一个显示允许的数组声明的演示程序
#include <stdio.h>
int a[][3];
int main(void)
{
extern int a[][3];
for ( size_t i = 0; i < 3; i++ )
{
a[0][i] = i;
}
for ( size_t i = 0; i < 3; i++ )
{
printf( "%d ", a[0][i] );
}
putchar( '\n' );
return 0;
}
文件范围内的声明
int a[][3];
是暂定定义,等价于tp
int a[1][3];
编译器可以发出警告,指出声明 int a[][3] 被假定为声明为 int a[1][3]。
如果您将使用初始化器,例如
int a[][3] =
{
{ 1, 2, 3 },
{ 4, 5, 6 }
};
那么编译器将通过初始化器的数量来确定数组中元素的数量。上述数组的类型为int [2][3]。或者如果你会写例如
int a[][3] = { [10] = { 1, 2, 3 } };
那么数组将有 11 个元素。也就是说数组的类型将是int[11][3]。
您也可以使用不完整类型的数组作为函数参数,例如
void f( int a[][3] );
编译器会将参数调整为指向数组元素类型之类的指针类型
void f( int ( *a )[3] );
也就是说,这两个函数声明声明了同一个函数,并且两者可以同时出现在程序中,尽管编译器会发出一条消息,指出存在冗余声明。
有趣的是,带有可变长度数组参数的函数声明不能被声明为例如
void f( size_t, size_t, int[*][*] );
您也可以声明一个指向不完整数组类型的指针,前提是您不会取消引用该指针。这是一个演示程序。
#include <stdio.h>
int main(void)
{
int ( *p )[];
printf( "sizeof( p ) = %zu\n", sizeof p );
return 0;
}
它的输出可能看起来像
sizeof( p ) = 8