繁体   English   中英

指向整数数组的指针的标量初始值设定项的多余元素

[英]Excess elements of scalar initializer for pointer to array of ints

我正在 K&R 中进行练习(例如 5-9),并且我试图将原始程序的二维数组转换为

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 ,并且编译器生成一个警告,让您知道您已经指定了许多刚刚被丢弃的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));

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

两种变体的“等价”仅意味着二维数组,当它衰减到指向其第一个元素的指针时,衰减到第二个变体中声明的指针类型。 一旦指针版本实际指向一个数组,两者是等价的。 但是二维数组版本为数组设置了内存,其中指针声明没有......并且可以为指针分配一个新值(指向不同的数组),而二维数组变量则不能。

但是,在 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}
};

@Dmitri 解释得很好,但我想补充一点

static char (*daytab)[13] = { ... };

一个指向 13 个char元素数组的指针。 编译器向您发出警告,因为您传入了两个数组。 这就像尝试将两个地址分配给一个指针char *p = {a, b} 根据您的声明,元素过多。 请参阅Geekforgeek对数组指针真正含义的解释

至于回答 K&R 练习,请考虑

选项1:

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

或选项 2:

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}
    };} 

选项 1 是一个包含两个char指针的数组。

选项 2 是一个数组指针。 它指向一个包含 13 个char元素的数组。 就像你可以增加一个char指针来获取字符串中的下一个字母一样,你可以增加这个数组指针来获取下一个 13 个char的数组。

我自己刚刚在 K&R 中解决了这个问题,所以也许我可以添加到已经给出的非常好的答案中。 这是摆脱使用二维数组而转向使用指针数组的一个很好的练习。 请注意,在本书的这一点上,我们还没有介绍malloc 因此,一种方法是预先设置月份数组,然后是指向这些数组的指针数组:

char y0[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
char y1[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
char *daytab[] = {y0, y1};

回想一下,数组的名称是指向第一个元素的指针。 现在你真的有一个指向两个 13 个int数组的指针数组。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM