首页 文章

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

提问于
浏览
832

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

19 回答

  • 61

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

    // put values 1-8, then two zeroes
    int list[10] = {1,2,3,4,5,6,7,8};
    
  • 5

    没有人提到索引顺序来访问初始化数组的元素 . 我的示例代码将给出一个说明性示例 .

    #include <iostream>
    
    void PrintArray(int a[3][3])
    {
        std::cout << "a11 = " << a[0][0] << "\t\t" << "a12 = " << a[0][1] << "\t\t" << "a13 = " << a[0][2] << std::endl;
        std::cout << "a21 = " << a[1][0] << "\t\t" << "a22 = " << a[1][1] << "\t\t" << "a23 = " << a[1][2] << std::endl;
        std::cout << "a31 = " << a[2][0] << "\t\t" << "a32 = " << a[2][1] << "\t\t" << "a33 = " << a[2][2] << std::endl;
        std::cout << std::endl;
    }
    
    int wmain(int argc, wchar_t * argv[])
    {
        int a1[3][3] =  {   11,     12,     13,     // The most
                            21,     22,     23,     // basic
                            31,     32,     33  };  // format.
    
        int a2[][3] =   {   11,     12,     13,     // The first (outer) dimension
                            21,     22,     23,     // may be omitted. The compiler
                            31,     32,     33  };  // will automatically deduce it.
    
        int a3[3][3] =  {   {11,    12,     13},    // The elements of each
                            {21,    22,     23},    // second (inner) dimension
                            {31,    32,     33} };  // can be grouped together.
    
        int a4[][3] =   {   {11,    12,     13},    // Again, the first dimension
                            {21,    22,     23},    // can be omitted when the 
                            {31,    32,     33} };  // inner elements are grouped.
    
        PrintArray(a1);
        PrintArray(a2);
        PrintArray(a3);
        PrintArray(a4);
    
        // This part shows in which order the elements are stored in the memory.
        int * b = (int *) a1;   // The output is the same for the all four arrays.
        for (int i=0; i<9; i++)
        {
            std::cout << b[i] << '\t';
        }
    
        return 0;
    }
    

    输出是:

    a11 = 11                a12 = 12                a13 = 13
    a21 = 21                a22 = 22                a23 = 23
    a31 = 31                a32 = 32                a33 = 33
    
    a11 = 11                a12 = 12                a13 = 13
    a21 = 21                a22 = 22                a23 = 23
    a31 = 31                a32 = 32                a33 = 33
    
    a11 = 11                a12 = 12                a13 = 13
    a21 = 21                a22 = 22                a23 = 23
    a31 = 31                a32 = 32                a33 = 33
    
    a11 = 11                a12 = 12                a13 = 13
    a21 = 21                a22 = 22                a23 = 23
    a31 = 31                a32 = 32                a33 = 33
    
    11      12      13      21      22      23      31      32      33
    
  • 4

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

    int myArray[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    

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

    int myPoints[][3] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9} };
    

    没关系,但是

    int myPoints[][] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9} };
    

    不是 .

  • 1082
    int i;
    for (i = 0; i < ARRAY_SIZE; ++i)
    {
      myArray[i] = VALUE;
    }
    

    我认为这比

    int myArray[10] = { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5...
    

    加入数组大小的变化 .

  • 164

    如果数组碰巧是int或任何大小为int的内容,或者你的mem-pattern的大小恰好适合int(即全零或0xA5A5A5A5),最好的方法是使用memset() .

    否则在移动索引的循环中调用memcpy() .

  • 0

    通过所有的讨论,简短的回答是,如果你在编译时打开优化,你将不会做得更好:

    int i,value=5,array[1000]; 
    for(i=0;i<1000;i++) array[i]=value;
    

    额外奖励:代码实际上清晰可见:)

  • -1

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

    #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

  • 0

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

    char* array[] = 
    {
        [0] = "Hello",
        [1] = "World"
    };
    

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

    enum
    {
        ERR_OK,
        ERR_FAIL,
        ERR_MEMORY
    };
    
    #define _ITEM(x) [x] = #x
    
    char* array[] = 
    {
        _ITEM(ERR_OK),
        _ITEM(ERR_FAIL),
        _ITEM(ERR_MEMORY)
    };
    

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

    有关此技术的更多信息,请参见herehere .

  • 11

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

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

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

  • 0

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

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

    int myArray[10] = { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 };
    

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

    int myArray[10] = { 1, 2 }; // initialize to 1,2,0,0,0...
    

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

    int myArray[10] = { 0 }; // all elements 0
    

    在C中,空的初始化列表也会将每个元素初始化为0.这是带有C的not allowed

    int myArray[10] = {}; // all elements 0 in C++
    

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

    static int myArray[10]; // all elements 0
    

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

  • 1

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

    • 初始化数组的第一个元素(通常的方式)

    • 复制已设置为尚未设置的部分,将每次下一次复制操作的大小加倍


    对于 1 000 000 elements int array,它比常规循环初始化快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;
    }
    
  • 2

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

    int array[1024] = {[0 ... 1023] = 5};
    

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

  • 22

    对于延迟初始化(即类成员构造函数初始化),请考虑:

    int a[4];
    
    unsigned int size = sizeof(a) / sizeof(a[0]);
    for (unsigned int i = 0; i < size; i++)
      a[i] = 0;
    
  • 46
    #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;
    }
    

    它将给出o / p 5 5 5 5 5 5 ......直到整个阵列的大小

  • 5

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

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

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

    编辑:可能有用的扩展

    Jonathan Leffler提供)

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

    #define VAL_1(X) X
    #define VAL_2(X) VAL_1(X), VAL_1(X)
    /* etc. */
    

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

    #define STRUCTVAL_1(...) { __VA_ARGS__ }
    #define STRUCTVAL_2(...) STRUCTVAL_1(__VA_ARGS__), STRUCTVAL_1(__VA_ARGS__)
    /*etc */
    

    适用于结构或复合数组 .

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

    宏名称可以协商 .

  • 1

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

    array = initial_value
    

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

  • 3

    我知道用户 Tarski 以类似的方式回答了这个问题,但我补充了一些细节 . 原谅我的一些C,因为我更倾向于想要使用C,但现在就这样了 .


    如果你提前知道阵列的大小......

    #include <stdio.h>
    
    typedef const unsigned int cUINT;
    typedef unsigned int UINT;
    
    cUINT size = 10;
    cUINT initVal = 5;
    
    void arrayInitializer( UINT* myArray, cUINT size, cUINT initVal );
    void printArray( UINT* myArray ); 
    
    int main() {        
        UINT myArray[size]; 
        /* Not initialized during declaration but can be
        initialized using a function for the appropriate TYPE*/
        arrayInitializer( myArray, size, initVal );
    
        printArray( myArray );
    
        return 0;
    }
    
    void arrayInitializer( UINT* myArray, cUINT size, cUINT initVal ) {
        for ( UINT n = 0; n < size; n++ ) {
            myArray[n] = initVal;
        }
    }
    
    void printArray( UINT* myArray ) {
        printf( "myArray = { " );
        for ( UINT n = 0; n < size; n++ ) {
            printf( "%u", myArray[n] );
    
            if ( n < size-1 )
                printf( ", " );
        }
        printf( " }\n" );
    }
    

    上面有一些警告;一个是 UINT myArray[size]; 在声明时没有直接初始化,但是下一个代码块或函数调用会将数组的每个元素初始化为您想要的相同值 . 另一个警告是,你必须为你支持的每个 type 写一个 initializing function ,你还必须修改 printArray() 函数来支持这些类型 .


    您可以使用在线编译器here尝试此代码 .

  • 357
    • 如果您的数组声明为静态或是全局的,则数组中的所有元素都具有默认的默认值0 .

    • 有些编译器在调试模式下将数组的默认值设置为0 .

    • 确实如此容易设置默认为0:int array [10] = {0};

    • 但是,对于其他值,您使用了memset()或loop;

    示例:int array [10]; memset(array,-1,10 * sizeof(int));

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

    看到:

    C-Extensions

    指定的内容

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

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

相关问题