【问题标题】:Can I use scalar initialization in a struct whose member is a pointer to pointer?我可以在其成员是指针指针的结构中使用标量初始化吗?
【发布时间】:2019-07-21 22:56:24
【问题描述】:

我有一个只有一个成员的结构。这个成员实际上是一个指向整数的指针,用来表示一个二维整数数组。

我可以在创建该结构的实例时使用标量初始化吗?

我正在尝试创建一个二维数组来表示用于算法练习的像素集合。

我应该代表这样的东西:

{
  { 0, 0, 1, 0, 0 },
  { 0, 1, 1, 1, 0 },
  { 1, 1, 1, 1, 1 }
}

为了表示图像的通用抽象,我尝试创建具有以下结构的结构:

struct image_t
{
  unsigned short int** pixels;
};

所以我尝试使用以下方法初始化一个实例:

int
main()
{
  struct image_t image = {
    {
      {0, 0, 1, 0, 0},
      {0, 1, 1, 1, 0},
      {1, 1, 1, 1, 1},
    }
  };

  return 0;
}

当我尝试编译时,会给出以下警告:

gcc -I src src/main.c -o bin/flood-fill.bin
src/main.c: In function ‘main’:
src/main.c:41:5: warning: braces around scalar initializer
     {
     ^
src/main.c:41:5: note: (near initialization for ‘image.pixels’)
src/main.c:42:7: warning: braces around scalar initializer
       {0, 1, 0},
       ^
src/main.c:42:7: note: (near initialization for ‘image.pixels’)
src/main.c:42:11: warning: excess elements in scalar initializer
       {0, 1, 0},
           ^
src/main.c:42:11: note: (near initialization for ‘image.pixels’)
src/main.c:42:14: warning: excess elements in scalar initializer
       {0, 1, 0},

在进行了一些研究后,我意识到,由于它将是一个图像表示,每一行将有相同的列总数。因此,我可以只使用一个数组并将所有内容存储在一个内存块中。 它解决了我的问题

但是,作为一个好奇的人,我想知道在这种情况下是否有任何方法可以使用标量初始化 - 如果有,我该怎么做?

很可能我遗漏了 C 语言中的一些关键的基本概念,因此非常欢迎解释。我真的很想更好地了解它的工作原理。

【问题讨论】:

  • 编译器会警告您有关标量初始值设定项中的多余元素,因为它期望pixels 有一个初始值,而您有一个用大括号括起来的列表。外大括号很好; image 是一个结构体,它的初始值应该用大括号括起来。在这些里面,应该有一个值,pixels 的初始值。由于pixelsunsigned short **,因此初始值应该是指向unsigned short 的指针的指针或空指针。 pixels 是一个指针,所以你不能用一个数组来初始化它。
  • 当然,您可以使用标量初始化——pixels 是一个标量,因此,要对其进行初始化,请给出一个值。但这不是你真正想要的。您对unsigned short** pixels 的声明表明您希望像素是一个二维数组,并且您被建议误导使用指向指针的指针来形成二维数组。一般来说,二维数组应该是数组数组(静态分配或自动分配时)或指向数组的指针(动态分配时,如malloc)。
  • 在您的情况下,如果列数是常量(使用#define 定义)Columns,您可以通过将pixels 的声明更改为unsigned short (*pixels)[Columns]; 来开始。然后用数据创建一个数组,就像unsigned short MyData[Rows][Columns] = { { 0, 0, 1, 0, 0 }, { 0, 1, 1, 1, 0 }, { 1, 1, 1, 1, 1 } };一样,然后用struct image_t image = { MyData };定义image。可以对此进行改进,但这是一种合理的开始方式。
  • 非常感谢您的回答,@EricPostpischil。由于我之前对数组(没有任何显式索引)的了解是指向其第一项的指针,因此我造成了这种混淆。这就是为什么我认为这个设计是正确的。现在它更干净了,因为它没有按预期工作。

标签: c struct


【解决方案1】:

这可能不是一个好主意,但您可以使用compound literals 创建您想要的结构,如下所示:

struct image_t
{
    unsigned short int **pixels;
};

int main(void)
{
    struct image_t image =
    {
        (unsigned short *[]) {
            (unsigned short []){ 0, 0, 1, 0, 0 },
            (unsigned short []){ 0, 1, 1, 1, 0 },
            (unsigned short []){ 1, 1, 1, 1, 1 },
        }
    };

    return image.pixels[1][4];
}

请注意,显示的数据结构的问题之一是没有关于指针数组中有多少行的信息,也没有关于每行中有多少项的信息(并且不能保证每一行都是相同的长度与其他行相同)。仅凭这一点就足以有理由认为该结构已损坏(无论如何设计不佳)。如果您添加了有关行和列的信息,那么就可以了。

请注意,unsigned short **pixels; 不是指向二维数组的指针。它是一个指向(一个数组)指针的指针,这是完全不同的。

【讨论】:

  • 哎哟!复合文字的复合文字。完全同意介绍性的谨慎——但非常有创意的解决方案....
  • 非常感谢乔纳森。计划是在image_t 结构中再添加两个成员:widthheight,它们代表图像的大小。也许我可以使用您的方法,然后创建一个充当构造函数的函数,接收位、宽度、高度,然后按照您的建议使用限制每个维度的复合文字?
  • 有了尺寸信息,也是可行和可用的,但表示法相当不灵活。我展示的是某种技术上的绝技,但我可能会寻找一种更正统的方式来做这件事。在某种程度上,这取决于您需要多少这些初始化结构,以及附加的数组有多大。如果只有几个(例如 1..9)并且数组大小很小(例如 1..16),则可能没问题。不仅如此,您还应该开始查看生成初始化程序的代码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-04-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-27
相关资源
最近更新 更多