如何将数组的所有成员初始化为相同的值?

1160

我在 C 中有一个大型数组(如果这有区别的话,不是 C++)。我希望将所有成员初始化为相同的值。

我记得曾经知道一种简单的方法来做到这一点。虽然我可以在我的情况下使用 memset(),但是否有一种内置于 C 语法中的方法来实现这一点呢?


25
迄今为止,没有任何答案提到在C99及以上版本中可行的指定初始化符号。例如:enum { HYDROGEN = 1, HELIUM = 2, CARBON = 6, NEON = 10, … };struct element { char name[15]; char symbol[3]; } elements[] = { [NEON] = { "Neon", "Ne" }, [HELIUM] = { "Helium", "He" }, [HYDROGEN] = { "Hydrogen", "H" }, [CARBON] = { "Carbon", "C" }, … };。如果删除省略号,这些片段可以在C99或C11下编译通过。 - Jonathan Leffler
实际上,abelenky的答案使用了指定初始化器,但并不是完全形成的初始化代码。 - Rob11311
memset()可以帮助,但取决于数值。 - Nick
2
memset()特定讨论:https://dev59.com/qmw05IYBdhLWcg3wfx80 我认为它只适用于0。 - Ciro Santilli OurBigBook.com
@Nick memset() 只适用于值为 0UINT_MAX 和元素大小为 char 的数组。 - user16217248
1
@user16217248 也适用于“循环”数字,例如0x1212、0x0303等。;) 但是是的,大多数情况下您需要零。 - Nick
27个回答

1

如果数组的大小事先已知,可以使用Boost预处理器C_ARRAY_INITIALIZE宏来帮助您完成繁琐的工作:

#include <boost/preprocessor/repetition/enum.hpp>
#define C_ARRAY_ELEMENT(z, index, name) name[index]
#define C_ARRAY_EXPAND(name,size) BOOST_PP_ENUM(size,C_ARRAY_ELEMENT,name)
#define C_ARRAY_VALUE(z, index, value) value
#define C_ARRAY_INITIALIZE(value,size) BOOST_PP_ENUM(size,C_ARRAY_VALUE,value)

0
方法一:
int a[5] = {3,3,3,3,3}; 

正式的初始化技术。

方法2:

int a[100] = {0};

但值得注意的是

int a[10] = {1}; 

不要将所有值初始化为1

这种初始化方式仅适用于0

如果你只是这样做

int a[100];

一些编译器倾向于采用垃圾值,因此最好这样做。

int a[1000] = {0};

0

作为Clemens Sielaff答案的跟进,这个版本需要C++17。

template <size_t Cnt, typename T>                                               
std::array<T, Cnt> make_array_of(const T& v)                                           
{                                                                               
    return []<size_t... Idx>(std::index_sequence<Idx...>, const auto& v)        
    {                                                                           
        auto identity = [](const auto& v, size_t) { return v; };                
        return std::array{identity(v, Idx)...};                                 
    }                                                                           
    (std::make_index_sequence<Cnt>{}, v);                                       
}

你可以在这里看到它的效果。


0
我会说指定初始化器是迄今为止最好的解决方案,但有一个特殊情况无法应用它们:
1. 你必须使用预先不知道大小的配置来初始化一个数组; 2. 数组的元素不能为零; 3. 由于某种原因,你不能使用gcc语法。
如果允许使用宏,你可以使用预处理器。
// macros.h
#define INDEX_SEQUENCE(X) _indexseq_expand(X)
#define _indexseq_expand(X) _indeseq_concat(_indexseq, X)

#define _indexseq_concat(a, b) _indexseq_concat_expand(a, b)
#define _indexseq_concat_expand(a, b) a##b

#define _indexseq1 0
#define _indexseq2 _indexseq1, 1
// generate as above to a given max size

#define APPLY_FOR_EACH(macro, ...) _foreach(macro, _vaargsn(__VA_ARGS__), __VA_ARGS__)
#define _foreach(macro, n, ...) _foreach_concat(_foreach, n)(macro, __VA_ARGS__)

#define _foreach_concat(a, b) _foreach_concat_expand(a, b)
#define _foreach_concat_expand(a, b) a##b

#define _foreach1(macro, i) macro(i)
#define _foreach2(macro, i, ...) macro(i) _foreach1(__VA_ARGS__)
// generate as above to a given max size

#define _vaargsn(...) _vaargsnpp(__VA_ARGS__, _vaargsnidx())
// macros below shall be generated as well until a given max size
#define _vaargsnpp(_1, _2, _3, N, ...) N
#define _vaargsnidx() 3, 2, 1

你可以这样初始化你的数组:
#define CONFIGURED_SIZE 42

struct complex_struct {
    int zero, one;
    float pi;
    unsigned index;
};

#define INIT(I) { 0, 1, 3.14159f, I },
struct complex_struct array[CONFIGURED_SIZE] = {
    APPLY_FOR_EACH(INIT, INDEX_SEQUENCE(CONFIGURED_SIZE))
};

限制:
- 编译器的预处理器宏扩展大小有限 - CONFIGURED_SIZE 必须是一个纯整数,不允许使用表达式或后缀

-1

回到过去的日子里(我并不是说这是一个好主意),我们会设置第一个元素,然后:

memcpy (&element [1], &element [0], sizeof (element)-sizeof (element [0]);

甚至不确定它现在是否还能工作(这取决于memcpy的实现),但它通过重复将初始元素复制到下一个元素来工作 - 甚至适用于结构体数组。


那样做不可靠。在我看来,标准应该提供类似于memcpy的函数,但在重叠的情况下指定自下而上或自上而下的复制顺序,但它没有这样做。 - supercat
正如我所说的,这只是我们做的一些事情,不能可靠地工作,但是当时,我们更注重效率而不是避免未记录的功能。虽然向前复制内存更有效,但规范中并没有说明它不能向后复制,随机顺序或在多个线程中分割。memmove()提供了无冲突的复制能力。 - Mike
这相当于另一个答案中的代码,但是有缺陷。使用memmove()并不能使其正常工作。 - Jonathan Leffler

-2
#include<stdio.h>
int main(){
int i,a[50];
for (i=0;i<50;i++){
    a[i]=5;// set value 5 to all the array index
}
for (i=0;i<50;i++)
printf("%d\n",a[i]);
   return 0;
}

它将输出5 5 5 5 5 5 ...... 直到整个数组的大小


-2

我在问题中没有看到任何要求,因此解决方案必须是通用的:初始化一个可能是多维数组的未指定可能是结构元素的数组,并具有初始成员值:

#include <string.h> 

void array_init( void *start, size_t element_size, size_t elements, void *initval ){
  memcpy(        start,              initval, element_size              );
  memcpy( (char*)start+element_size, start,   element_size*(elements-1) );
}

// testing
#include <stdio.h> 

struct s {
  int a;
  char b;
} array[2][3], init;

int main(){
  init = (struct s){.a = 3, .b = 'x'};
  array_init( array, sizeof(array[0][0]), 2*3, &init );

  for( int i=0; i<2; i++ )
    for( int j=0; j<3; j++ )
      printf("array[%i][%i].a = %i .b = '%c'\n",i,j,array[i][j].a,array[i][j].b);
}

结果:

array[0][0].a = 3 .b = 'x'
array[0][1].a = 3 .b = 'x'
array[0][2].a = 3 .b = 'x'
array[1][0].a = 3 .b = 'x'
array[1][1].a = 3 .b = 'x'
array[1][2].a = 3 .b = 'x'

编辑:将start+element_size更改为(char*)start+element_size


1
我对这是否是一个解决方案持怀疑态度。我不确定 sizeof(void) 是否有效。 - Chris Lutz
3
无法运行。只有前两个被初始化,其余的都未初始化。我在Mac OS X 10.4上使用GCC 4.0。 - dreamlax
这会引发未定义的行为,因为第二个memcpy()中的源数据与目标空间重叠。使用天真的memcpy()实现可能会起作用,但系统不要求它能够正常工作。 - Jonathan Leffler

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接