我正在K&R(例如5–9)中进行练习,并且尝试转换原始程序的2D数组

static char daytab[2][13] = {
    {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
    {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};

使用指向13个整数的数组的指针,例如
static char (*daytab)[13] = {
    {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
    {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};

但是编译器会打印警告:标量初始化程序中的多余元素。

谷歌搜索没有帮助,甚至在将数组传递给函数时,K&R也会写,
myFunction(int daytab[2][13]) {...}

是相同的
myFunction(int (*daytab)[13]) {...}

最佳答案

两者只是部分等效。区别在于:

static char daytab[2][13] = {
    {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
    {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};

声明一个二维数组,该数组包括为数组留出空间并确保daytab引用该内存。然而:
static char (*daytab)[13] = {
    {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
    {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};

...仅声明一个指针。因此,您尝试使用数组初始值设定项初始化指针,该指针未按预期工作。没有数组。没有为阵列留出任何内存。相反,发生的事情是将初始化程序中的第一个数字分配给指针daytab,并且编译器生成警告,以告知您已经指定了很多其他值,这些值刚刚被丢弃。由于初始化器中的第一个数字是0,因此您只是以一种相当冗长的方式将daytab设置为NULL

因此,如果要执行此类初始化,请使用第一个版本-它会衰减为您在第二个版本中明确声明的指针类型,因此您可以使用相同的方式。当您希望动态分配数组或获取对另一个已经存在的数组的引用时,需要带有数组指针的第二个版本。

因此,您可以执行以下操作:
static char arr[2][3] = { { 1, 2, 3 }, { 4, 5, 6 } };
static char (*ptr)[3] = NULL;

ptr = arr;

...然后交替使用ptrarr。或这个:
static char (*ptr)[3] = NULL;

ptr = malloc(2 * sizeof(*ptr));

...以获得动态分配的二维数组(不是指向1D数组的指针数组,而是真正的2D数组)。当然,在这种情况下不会初始化。

两个变体的“等效性”仅表示2D数组在衰减到指向其第一个元素的指针时,会衰减到在第二个变形中声明的指针的类型。一旦指针版本实际上指向一个数组,则两者是等效的。但是2D数组版本会为该数组设置内存,在该内存中指针声明不会...并且可以为指针分配2D数组变量不能的新值(指向另一个数组)。

但是,在C99中,您可以执行此操作(如果至少不是static):
char (*daytab)[13] = (char [][13]){
    {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
    {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};

09-04 14:40
查看更多