Array of Length Zero

Zero-length arrays are allowed in GNU C. They are very useful as the last element of a structure which really a header for a variable-length object:

struct line {
	int length;
	char contents[0];
};

struct line *thisline = (struct line *)
	malloc (sizeof (struct line) + this_length);
thisline->length = this_length;

这是 GNU 官方文档 里的例子。零长数组非常有用,尤其作为可变长对象的最后一个元素时,可以根据对象的大小动态分配内存。这是在 ISO C99 里出现的,在 C90 中,数组元素必须至少为 1。

VLA (variable length array)

VLA 即为变长数组,这也是 C99 中出现的新特性,但并不是说程序运行中的数组的长度可变,而是指数组定义时的长度可以使用变量。如:

int n;
scanf("%d", &n);
int a[n];

这可以用在函数里,函数结束时变长数组的内存空间会被自动释放,非常有用,就像 alloca() 函数一样。

但是,变长数组也有诸多限制:

All declarations of variably modified (VM) types have to be at either block scope or function prototype scope. Array objects declared with the static or extern storage class specifier cannot have a variable length array (VLA) type. However, an object declared with the static storage class specifier can have a VM type (that is, a pointer to a VLA type). Finally, all identifiers declared with a VM type have to be ordinary identifiers and cannot, therefore, be members of structures or unions.

这段话和下面的例子都来自 ISO C99 标准 6.7.5.2 Array declarators

extern int n;                
int A[n];                          // Error - file scope VLA.
extern int (*p2)[n];               // Error - file scope VM.
int B[100];                        // OK - file scope but not VM.

void fvla(int m, int C[m][n])      // OK - VLA with prototype scope.
{
	typedef int VLA[m][n];     // OK - block scope typedef VLA.

	struct tag {
		int (*y)[n];       // Error - y not ordinary identifier.
		int z[n];          // Error - z not ordinary identifier.
	};
	int D[m];                  // OK - auto VLA.
	static int E[m];           // Error - static block scope VLA.
	extern int F[m];           // Error - F has linkage and is VLA.
	int (*s)[m];               // OK - auto pointer to VLA.
	extern int (*r)[m];        // Error - r had linkage and
                                        // is a pointer to VLA.

	static int (*q)[m] = &B;   // OK - q is a static block pointer to VLA.
}

原文中的 typtdef 一句缺少分号,这里已经加上了(如果发现原文已经修改,而我仍未修改,可以通过邮件联系我)。