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

Mat*_*att 934 c arrays array-initialize initialization

我在C中有一个大数组(如果有所不同,则不是C++).我想将所有成员初始化为相同的值.我发誓我曾经知道一个简单的方法来做到这一点.我可以memset()在我的情况下使用,但是没有办法在C语法中构建这样做吗?

aib*_*aib 1195

除非该值为0(在这种情况下,您可以省略初始化程序的某些部分,并且相应的元素将初始化为0),否则没有简单的方法.

但是,不要忽视明显的解决方案:

int myArray[10] = { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 };
Run Code Online (Sandbox Code Playgroud)

缺少值的元素将初始化为0:

int myArray[10] = { 1, 2 }; // initialize to 1,2,0,0,0...
Run Code Online (Sandbox Code Playgroud)

所以这会将所有元素初始化为0:

int myArray[10] = { 0 }; // all elements 0
Run Code Online (Sandbox Code Playgroud)

在C++中,空的初始化列表也会将每个元素初始化为0. C 不允许这样做:

int myArray[10] = {}; // all elements 0 in C++
Run Code Online (Sandbox Code Playgroud)

请记住,如果未指定初始化程序,具有静态存储持续时间的对象将初始化为0:

static int myArray[10]; // all elements 0
Run Code Online (Sandbox Code Playgroud)

而"0"并不一定意味着"所有位为零",因此使用上述内容比memset()更好,更便携.(浮点值将初始化为+0,指向空值的指针等)

  • 查看第6.7.8节C99标准的初始化,似乎不允许使用空的初始化列表. (52认同)
  • 通过C++标准阅读,你也可以做int array [10] = {}; 初始化为零.我没有C标准来检查这是否也是有效的C. (24认同)
  • @CetinSert:在该评论中,您是唯一声称所有元素都设置为-1的人.这个答案正确地声称所有未指定的元素都设置为零.您的代码结果与此声明一致. (9认同)
  • @CetinSert:你的意思是什么不起作用?它正是这个答案所说的应该做的.它没有执行代码中的注释所说的内容,但该注释是错误的. (8认同)
  • C99有很多很好的结构和数组初始化功能; 它没有的一个功能(但Fortran IV,1966,有)是一种为数组重复特定初始化器的方法. (7认同)
  • `int myArray[10] = { -1 };` 只是不起作用,请参阅 http://codepad.org/ckuy54OZ !! (2认同)
  • @BenjaminLindley 你看到 `int myArray[10] = { 0 }; 中的评论了吗?//来自答案的所有元素 0`?好吧,当我使用 `-1` 代替时,它是 * 仅第一个 * 元素设置为 `-1` 而 * 不是所有 * 所声称的。键盘链接有一段代码来证明建议 `= { x };` 赋值确实将 *all* 元素设置为 `x` 是错误的。我希望其他人看到这一点。 (2认同)
  • 我想我还没见过这个: `int myArray[] = {[3] = 123, [7] = 23};` 给你 `{0, 0, 0, 123, 0, 0, 0 , 23}` (2认同)
  • @akofink:在下面查看qrdl的答案.这是GCC扩展. (2认同)
  • @Fratink 请参阅第 6.7.8.21 节:“如果大括号括起来的列表中的初始值设定项少于聚合的元素或成员,或者用于初始化已知大小的数组的字符串文字中的字符少于其中的元素数组中,聚合的其余部分应与具有静态存储持续时间的对象一样隐式初始化。” (2认同)

qrd*_*rdl 383

如果您的编译器是GCC,您可以使用以下语法:

int array[1024] = {[0 ... 1023] = 5};
Run Code Online (Sandbox Code Playgroud)

查看详细说明:http: //gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Designated-Inits.html

  • @CetinSert编译器必须将65536`int`s添加到静态数据中,这是256 K - 正是您观察到的大小增加. (44认同)
  • 更好的是:"int array [] = {[0 ... 1023] = 5}",数组的大小将自动设置为1024,修改起来更容易,更安全. (26认同)
  • @CetinSert我为什么要这样?它是标准编译器行为,不是特定于指定的初始化程序.如果你静态初始化65536`int`s,比如`int foo1 = 1,foo2 = 1,...,foo65536 = 1;`你将获得相同的大小增加. (14认同)
  • 并且该语法导致编译的二进制文件的文件大小大幅增加.对于N = 65536(而不是1024),我的二进制文件从15 KB跳到270 KB! (12认同)
  • @Francois或2d数组,`bool array [] [COLS] = {[0 ... ROWS-1] [0 ... COLS-1] = true}`,虽然我不确定它是否更具可读性比完整的形式. (4认同)
  • @abhi你想做的不是初始化而是赋值,这种语法不能在这种情况下使用,你最好使用`memset()` (2认同)
  • 我想当你说`gcc`时它也适用于`g ++`. (2认同)
  • @AkshayImmanuelD 请从一开始阅读与 Cetin Sert 的讨论 (2认同)

mou*_*iel 176

要静态初始化具有相同值的大型数组,而不使用多个复制粘贴,您可以使用宏:

#define VAL_1X     42
#define VAL_2X     VAL_1X,  VAL_1X
#define VAL_4X     VAL_2X,  VAL_2X
#define VAL_8X     VAL_4X,  VAL_4X
#define VAL_16X    VAL_8X,  VAL_8X
#define VAL_32X    VAL_16X, VAL_16X
#define VAL_64X    VAL_32X, VAL_32X

int myArray[53] = { VAL_32X, VAL_16X, VAL_4X, VAL_1X };
Run Code Online (Sandbox Code Playgroud)

如果您需要更改该值,则必须仅在一个地方进行更换.

编辑:可能有用的扩展

(Jonathan Leffler提供)

您可以通过以下方式轻松概括:

#define VAL_1(X) X
#define VAL_2(X) VAL_1(X), VAL_1(X)
/* etc. */
Run Code Online (Sandbox Code Playgroud)

可以使用以下方法创建变体:

#define STRUCTVAL_1(...) { __VA_ARGS__ }
#define STRUCTVAL_2(...) STRUCTVAL_1(__VA_ARGS__), STRUCTVAL_1(__VA_ARGS__)
/*etc */ 
Run Code Online (Sandbox Code Playgroud)

适用于结构或复合数组.

#define STRUCTVAL_48(...) STRUCTVAL_32(__VA_ARGS__), STRUCTVAL_16(__VA_ARGS__)

struct Pair { char key[16]; char val[32]; };
struct Pair p_data[] = { STRUCTVAL_48("Key", "Value") };
int a_data[][4] = { STRUCTVAL_48(12, 19, 23, 37) };
Run Code Online (Sandbox Code Playgroud)

宏名称可以协商.

  • 如果数据必须是可ROM的,则不能使用memset. (46认同)
  • 我只会在极端情况下考虑这一点,当然memset是表达它的更优雅的方式. (12认同)
  • 预处理器实际上会从#defines生成代码.使用更大的数组维度,可执行文件的大小 但绝对+的想法;) (9认同)
  • @Alcott,在旧计算机上,仍然在许多嵌入式系统上,代码最终放在[EPROM](http://en.wikipedia.org/wiki/EPROM"维基百科上的EPROM解释")或[ROM](http)中://en.wikipedia.org/wiki/Read-only_memory"维基百科的ROM解释").ROM-able也意味着,在嵌入式系统中,"代码放入闪存",因为它具有大致相同的含义,即内存不能写入运行时.即memset或任何其他更新或更改内存的指令都不能使用.但是,常量可以在程序启动之前表达,闪烁或ROM编辑. (7认同)
  • @ u0b34a0f6ae:请记住,如果`VAL_1X`不是单个整数而是列表,也可以使用此方法.与Amigable状态一样,这也是您想要定义EEPROM或闪存的初始值的嵌入式系统的方法.在这两种情况下,你都不能使用`memset()`. (4认同)
  • memset用char初始化.它不能用于将int数组初始化为42之类的值.值0可用于初始化为零.值-1可用于将数组初始化为-1. (3认同)
  • 您可以使用#define VAL_1(X)X和#define VAL_2(X)VAL_1(X),VAL_1(X)等轻松地对此进行概括。可以使用#define STRUCTVAL_1(... } {__VA_ARGS__}`和`#define STRUCTVAL_2(...)STRUCTVAL_1(__ VA_ARGS__),STRUCTVAL_1(__ VA_ARGS __)`等适用于结构或复合数组的对象。#define STRUCTVAL_48(...)STRUCTVAL_32(__ VA_ARGS__),STRUCTVAL_16(__ VA_ARGS__)和struct Pair {char key [16]; char val [32]; };`和`struct Pair p_data [] = {STRUCTVAL_48(“ Key”,“ Value”)};`和`int a_data [] [4] = {STRUCTVAL_48(12,19,23,37)};`—宏名称可以协商。 (2认同)

Fra*_*rba 62

如果要确保显式初始化数组的每个成员,只需省略声明中的维:

int myArray[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
Run Code Online (Sandbox Code Playgroud)

编译器将从初始化列表中推断出维度.不幸的是,对于多维数组,只能省略最外层的维度:

int myPoints[][3] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9} };
Run Code Online (Sandbox Code Playgroud)

没关系,但是

int myPoints[][] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9} };
Run Code Online (Sandbox Code Playgroud)

不是.

  • 不.您省略了最内层的维度,这是不允许的.这将给出编译器错误. (8认同)
  • 初始化器和长度推断均在C99中引入. (4认同)
  • @Palec:从标准C之前的日子开始就没有 - 长度推断(自K&R第1版发布以来,可能还需要一段时间).指定的初始化程序在C99中是新的,但这不是使用指定的初始化程序. (3认同)

abe*_*nky 49

我看到一些使用这种语法的代码:

char* array[] = 
{
    [0] = "Hello",
    [1] = "World"
};   
Run Code Online (Sandbox Code Playgroud)

如果您正在创建一个使用枚举作为索引的数组,它变得特别有用:

enum
{
    ERR_OK,
    ERR_FAIL,
    ERR_MEMORY
};

#define _ITEM(x) [x] = #x

char* array[] = 
{
    _ITEM(ERR_OK),
    _ITEM(ERR_FAIL),
    _ITEM(ERR_MEMORY)
};   
Run Code Online (Sandbox Code Playgroud)

这样可以使事情保持正常,即使您碰巧无序地编写了一些枚举值.

关于这种技术的更多信息可以在这里这里找到.

  • 这是C99初始化程序语法,已经被其他一些答案所涵盖.您可以有效地将声明声明为`char const*array [] = {...};`甚至`char const*const array [] = {...};`,不是吗? (7认同)

Tar*_*ski 22

int i;
for (i = 0; i < ARRAY_SIZE; ++i)
{
  myArray[i] = VALUE;
}
Run Code Online (Sandbox Code Playgroud)

我认为这比

int myArray[10] = { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5...
Run Code Online (Sandbox Code Playgroud)

加入数组大小的变化.

  • @Benson:你不能在sizeof(int)> sizeof(char)的平台上用memset替换上面的代码.试试吧. (21认同)
  • 你如何使用memset将int数组初始化为大于255的某个值?memset仅在数组为字节大小时才有效. (18认同)
  • 对于记录,这基本上只是一个更慢,更冗长的`memset(myArray,VALUE,ARRAY_SIZE)版本; (12认同)

pli*_*nth 13

你可以像上面详细描述的那样完成整个静态初始化器的事情,但是当你的数组大小改变时(当你的数组嵌入时,如果你没有添加适当的额外初始化器你得到垃圾),它可能是一个真正的无赖.

memset为您的工作提供了运行时命中,但没有正确执行的代码大小不受阵列大小更改的影响.几乎在所有情况下,当数组大于几十个元素时,我会使用此解决方案.

如果静态声明数组非常重要,我会编写一个程序来为我编写程序并使其成为构建过程的一部分.


hum*_*uru 8

这是另一种方式:

static void
unhandled_interrupt(struct trap_frame *frame, int irq, void *arg)
{
    //this code intentionally left blank
}

static struct irqtbl_s vector_tbl[XCHAL_NUM_INTERRUPTS] = {
    [0 ... XCHAL_NUM_INTERRUPTS-1] {unhandled_interrupt, NULL},
};
Run Code Online (Sandbox Code Playgroud)

看到:

C-扩展

指定的内容

然后问一个问题:什么时候可以使用C扩展?

上面的代码示例位于嵌入式系统中,永远不会看到来自其他编译器的光.


war*_*ren 6

对于初始化'普通'数据类型(如int数组),您可以使用括号表示法,但如果数组中仍有空格,它将在最后一个之后将值归零:

// put values 1-8, then two zeroes
int list[10] = {1,2,3,4,5,6,7,8};
Run Code Online (Sandbox Code Playgroud)


Hig*_*ark 6

一个略微诙谐的答案; 写下声明

array = initial_value
Run Code Online (Sandbox Code Playgroud)

用您最喜欢的支持数组的语言(我的是Fortran,但还有很多其他语言),并将其链接到您的C代码.你可能想把它包装成一个外部函数.


ddi*_*rov 5

如果数组恰好是int或任何具有int大小的东西,或者您的mem-pattern的大小适合于int的精确时间(即全零或0xA5A5A5A5),则最好的方法是使用memset()

否则,在循环中调用memcpy()来移动索引。


Mac*_*iej 5

有一种快速的方法可以用给定的值初始化任何类型的数组。它适用于大型阵列。算法如下:

  • 初始化数组的第一个元素(通常的方式)
  • 将已设置的部分复制到尚未设置的部分中,每次复制操作时将大小加倍

对于1 000 000元素int数组,它比常规循环初始化快 4 倍(i5,2 核,2.3 GHz,4GiB 内存,64 位):

loop runtime 0.004248 [seconds]

memfill() runtime 0.001085 [seconds]


#include <stdio.h>
#include <time.h>
#include <string.h>
#define ARR_SIZE 1000000

void memfill(void *dest, size_t destsize, size_t elemsize) {
   char   *nextdest = (char *) dest + elemsize;
   size_t movesize, donesize = elemsize;

   destsize -= elemsize;
   while (destsize) {
      movesize = (donesize < destsize) ? donesize : destsize;
      memcpy(nextdest, dest, movesize);
      nextdest += movesize; destsize -= movesize; donesize += movesize;
   }
}    
int main() {
    clock_t timeStart;
    double  runTime;
    int     i, a[ARR_SIZE];

    timeStart = clock();
    for (i = 0; i < ARR_SIZE; i++)
        a[i] = 9;    
    runTime = (double)(clock() - timeStart) / (double)CLOCKS_PER_SEC;
    printf("loop runtime %f [seconds]\n",runTime);

    timeStart = clock();
    a[0] = 10;
    memfill(a, sizeof(a), sizeof(a[0]));
    runTime = (double)(clock() - timeStart) / (double)CLOCKS_PER_SEC;
    printf("memfill() runtime %f [seconds]\n",runTime);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

  • 与任何基准测试代码一样,您需要非常小心。添加一个循环来执行计时代码 10 次(并将数组的大小加倍到 20M)显示 - 对我来说,在装有 macOS Sierra 10.12.3 并使用 GCC 6.3.0 的 MacBook Pro 上运行 - 第一次使用循环大约需要 4600 µs,而 `memfill()` 代码大约需要 1200 µs。然而,在随后的迭代中,循环大约需要 900-1000 微秒,而“memfill()”代码需要 1000-1300 微秒。第一次迭代可能会受到填充缓存时间的影响。逆向测试,并且 `memfill()` 第一次很慢。 (3认同)
  • 对不起,但这不是真的。也许您在测试期间忘记打开编译优化(使用调试模式测试?)。如果我对此进行测试,循环几乎总是比 memfill 快 50%(“总是”由于我的机器上的一些负载抖动)。并使用 memset(a,0,sizeof(a)); 甚至比循环填充快两倍。 (2认同)

Cle*_*aff 5

我知道最初的问题明确提到了 C 而不是 C++,但是如果你(像我一样)来这里寻找 C++ 数组的解决方案,这里有一个巧妙的技巧:

如果您的编译器支持折叠表达式,您可以使用模板魔术并使用std::index_sequence您想要的值生成一个初始化列表。你甚至constexpr可以感觉像一个老板:

#include <array>

/// [3]
/// This functions's only purpose is to ignore the index given as the second
/// template argument and to always produce the value passed in.
template<class T, size_t /*ignored*/>
constexpr T identity_func(const T& value) {
    return value;
}

/// [2]
/// At this point, we have a list of indices that we can unfold
/// into an initializer list using the `identity_func` above.
template<class T, size_t... Indices>
constexpr std::array<T, sizeof...(Indices)>
make_array_of_impl(const T& value, std::index_sequence<Indices...>) {
    return {identity_func<T, Indices>(value)...};
}

/// [1]
/// This is the user-facing function.
/// The template arguments are swapped compared to the order used
/// for std::array, this way we can let the compiler infer the type
/// from the given value but still define it explicitly if we want to.
template<size_t Size, class T>
constexpr std::array<T, Size> 
make_array_of(const T& value) {
    using Indices = std::make_index_sequence<Size>;
    return make_array_of_impl(value, Indices{});
}

// std::array<int, 4>{42, 42, 42, 42}
constexpr auto test_array = make_array_of<4/*, int*/>(42);
static_assert(test_array[0] == 42);
static_assert(test_array[1] == 42);
static_assert(test_array[2] == 42);
static_assert(test_array[3] == 42);
// static_assert(test_array[4] == 42); out of bounds
Run Code Online (Sandbox Code Playgroud)

你可以看看工作中的代码(在Wandbox)