【问题标题】:c structure array initializingc结构体数组初始化
【发布时间】:2014-02-26 23:51:17
【问题描述】:

我有结构

struct ABC {
  int a; 
  int b;
}

并将它的数组作为

struct ABC xyz[100];

我想初始化它 a = 10 and b = 20;对于所有数组元素。

哪种方法更好?

【问题讨论】:

  • 写一个循环?有什么问题?
  • 在你的代码中写 100 次!
  • GCC 扩展:struct ABC xyz[100] = {[0 ... 99] = {10, 20}};

标签: c arrays initialization structure


【解决方案1】:

没有明确的语言支持将子结构数组中的所有元素初始化为特定的非零默认值,就像将所有元素初始化为零一样;您要么必须在编译时显式初始化源代码中的每个元素,要么必须编写一个 for() 循环并在启动时初始化每个元素。

正如用户 @lundin 在另一个答案中指出的那样,您可以使用预处理器宏来减少显式初始化这些值所涉及的类型,但就 C 编译器而言,您仍在显式初始化每个元素。

【讨论】:

  • 在标准 C 中有这样的语言语法。运行时不需要循环。
  • 更新了答案以澄清存在的内容,而不是语法,因为第一个版本显然具有误导性。 @Lundin 基于预处理器的解决方案很聪明,但我认为仅仅因为您可以使用预处理器技巧完成某些事情,就声称“标准 C 中有 [something] 的语言语法”有点牵强。预处理器的行为可以在标准中指定,但它本身不是“C”。
  • 如果您可以使用完全确认的 C 编译器接受的某种机制来做到这一点,那么就可以使用 C 语法。关于预处理器是否为“C语法”,请参见标准附件A中的“语言语法摘要”:)
【解决方案2】:

虽然在 C 中没有特别优雅的方式来初始化这样的大数组,但这是可能的。正如一些答案错误地声称的那样,您不必在运行时执行此操作。而你不想在运行时这样做,假设数组是const?

我的做法是定义一些宏:

struct ABC {
  int a; 
  int b;
};

#define ABC_INIT_100 ABC_INIT_50 ABC_INIT_50
#define ABC_INIT_50  ABC_INIT_10 ABC_INIT_10 ABC_INIT_10 ABC_INIT_10 ABC_INIT_10
#define ABC_INIT_10  ABC_INIT_2 ABC_INIT_2 ABC_INIT_2 ABC_INIT_2 ABC_INIT_2
#define ABC_INIT_2   ABC_INIT_1 ABC_INIT_1
#define ABC_INIT_1   {10, 20},

int main()
{
  struct ABC xyz[100] =
  {
    ABC_INIT_100
  };
}

请注意,可以以任何方式组合此类宏,以进行任意数量的初始化。例如:

#define ABC_INIT_152 ABC_INIT_100 ABC_INIT_50 ABC_INIT_2

【讨论】:

    【解决方案3】:

    使用 GCC,您可以使用其 extended syntax 并执行以下操作:

    struct ABC xyz[100] = { [0 ... 99].a = 10, [0 ... 99].b = 20 };
    

    对于便携式解决方案,我可能会初始化一个实例,然后使用循环将该实例复制到其余实例:

    struct ABC xyz[100] = { [0].a = 10, [0].b = 20 };
    
    for(size_t i = 1; i < sizeof xyz / sizeof *xyz; ++i)
      xyz[i] = xyz[0];
    

    这对我来说比在循环中包含实际值要干净一些。可以说是在略高的层次上表达了想要的结果。

    上述语法([0].a[0].b不是扩展,它是典型的 C99。

    【讨论】:

    • 便携版严格来说不是初始化,而是运行时赋值。如果 xyz 是 const,你会怎么做?
    • @Lundin 当然,就像所有其他循环建议一样。我不认为它可以用const 来完成,没有一个大的显式初始化或宏(就像你的答案)。
    • @lundin 另一方面,如果有问题的数组是在函数内部的堆栈上分配的,并且数组大小是函数参数,您将如何使用宏?您可以通过添加额外要求使任何答案不适用,但没有迹象表明 OP 正在寻找 const 数组;鉴于问题的性质,他更有可能只是在寻找一种避免大量输入的方法(您的解决方案和基于循环的解决方案都提供了这种方法。)虽然它不是严格初始化,但它大多数人随便说的这个词的意思。
    • 另外,我喜欢这个版本更好地捕捉到将所有元素设置为相同默认值的意图,并且如果数组的大小发生变化(或者是动态的),它也不会中断。
    • @JVMATL 本地范围的 VLA 在运行时分配,因此使用初始化而不是分配没有任何好处。初始化和赋值之间的区别仅在谈到变量的默认值时才重要,这可以在编译时确定。
    【解决方案4】:
    for(unsigned int i=0; i<100; i++)
    {
        xyz[i].a = 10;
        xyz[i].b = 20;
    }
    

    【讨论】:

    • 这严格来说不是初始化,而是运行时赋值。如果 xyz 是 const,你会怎么做?
    • @Lundin 那么为什么您需要多个相同值的副本?
    • @rmartinjak 这完全取决于应用程序的性质。假设存在一种情况,其中所有值都是单独的,而另一种情况是它们都相同。然后使用 const 数组作为函数的输入。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-24
    相关资源
    最近更新 更多