【问题标题】:如何将数组的所有成员初始化为相同的值?
【发布时间】:2010-09-17 02:20:23
【问题描述】:

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

我可以发誓我曾经知道一个简单的方法来做到这一点。在我的情况下,我可以使用memset(),但是没有一种内置于 C 语法中的方法吗?

【问题讨论】:

  • 到目前为止,没有一个答案提到在 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 下编译。
  • 其实abelenky的回答是使用指定的初始化器,但是没有完全形成初始化代码
  • memset() 可以提供帮助,但取决于值。
  • memset()具体讨论:stackoverflow.com/questions/7202411/…我觉得只对0有效。

标签: c arrays initialization array-initialize


【解决方案1】:

除非该值为 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。 这是not allowed,带有 C:

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

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

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

而且“0”并不一定意味着“所有位为零”,所以使用上面是 比 memset() 更好、更便携。 (浮点值将是 初始化为 +0、指向空值的指针等)

【讨论】:

  • 通读C++标准,也可以做 int array[10] = {};归零初始化。不过,我没有 C 标准来检查这是否也是有效的 C。
  • 查看第 6.7.8 节 C99 标准的初始化,似乎不允许空的初始化列表。
  • C99 有很多很好的结构和数组初始化特性;它没有的一个功能(但 Fortran IV,1966 年有)是一种为数组重复特定初始化程序的方法。
  • @CetinSert:你是什么意思它不起作用?它完全按照这个答案所说的去做。它没有按照您代码中的注释所说的那样做,但是该注释是错误的。
  • @CetinSert:在该评论中,您是唯一一个声称所有元素都将设置为 -1 的人。这个答案正确地声称所有未指定的元素都设置为零。您的代码结果与此声明一致。
【解决方案2】:

如果您的编译器是 GCC,您可以使用以下“GNU 扩展”语法:

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

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

【讨论】:

  • 这种语法会导致编译后的二进制文件的文件大小大幅增加。对于 N = 65536(而不是 1024),我的二进制文件大小从 15 KB 跃升至 270 KB!
  • @CetinSert 编译器必须将 65536 ints 添加到静态数据中,即 256 K - 正是您观察到的大小增加。
  • @CetinSert 我为什么要这样做?这是标准的编译器行为,并不特定于指定的初始化程序。如果你静态初始化 65536 ints,比如int foo1 = 1, foo2 = 1, ..., foo65536 =1;,你会得到同样的大小增加。
  • 更好的是:"int array[] = {[0 ... 1023] = 5}",数组大小会自动设置为1024,修改起来更简单更安全。
  • @Francois 或二维数组 bool array[][COLS] = { [0...ROWS-1][0...COLS-1] = true},虽然我不确定这是否比完整形式更具可读性。
【解决方案3】:

为了静态初始化一个值相同的大数组,不需要多次复制粘贴,可以使用宏:

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

宏名称可以协商。

【讨论】:

  • 我只会在极端情况下考虑这个,当然 memset 是更优雅的表达方式。
  • 如果数据必须是ROM-able,则不能使用memset。
  • 预处理器实际上会从#defines 生成代码。随着更大的数组维度,可执行文件的大小将会增加。但绝对是 + 的想法;)
  • @Alcott,在旧计算机上以及许多嵌入式系统上,代码最终都放在EPROMROM 中。 ROM-able 在嵌入式系统中也意味着“代码放入闪存”,因为它具有大致相同的含义,即内存不能在运行时写入。 IE。不能使用 memset 或任何其他更新或更改内存的指令。不过,常量可以在程序启动之前进行表达、刷新或 ROM 化。
  • @u0b34a0f6ae:请记住,如果VAL_1X 不是单个整数而是列表,您也可以使用此方法。与 Amigable 状态一样,这也是您想要定义 EEPROM 或闪存的初始值的嵌入式系统的方法。在这两种情况下,您都不能使用memset()
【解决方案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} };

不是。

【讨论】:

  • 这是正确的吗? int myPoints[10][] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9} };
  • 没有。您省略了最里面的维度,这是不允许的。这将导致编译器错误。
  • 初始化器和长度推断都是在 C99 中引入的。
  • @Palec:不——自标准 C 时代以来,长度推断一直在 C 中(自 K&R 第 1 版发布以来,可能在此之前一段时间)。指定初始值设定项是 C99 中的新内容,但这没有使用指定初始值设定项。
【解决方案5】:

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

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 找到有关此技术的更多信息。

【讨论】:

  • 这是 C99 初始化语法,其他一些答案已经涵盖了。您可以有效地将声明变成char const *array[] = { ... }; 甚至char const * const array[] = { ... };,不是吗?
【解决方案6】:
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...

以防数组大小发生变化。

【讨论】:

  • 为了记录,这基本上只是memset(myArray, VALUE, ARRAY_SIZE);的一个更慢、更详细的版本
  • 如何使用 memset 将 int 数组初始化为大于 255 的某个值? memset 仅在数组为字节大小时才有效。
  • @Benson:在 sizeof(int) > sizeof(char) 的平台上,您不能用 memset 替换上述代码。试试看。
【解决方案7】:

您可以按照上面详述的方式完成整个静态初始化程序,但是当您的数组大小发生变化时(当您的数组发生变化时,如果您不添加适当的额外初始化程序,您会得到垃圾),这可能会非常糟糕。

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

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

【讨论】:

  • 能否添加一些关于使用memset 初始化数组的示例?
【解决方案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 扩展?

上面的代码示例是在嵌入式系统中,永远不会看到来自另一个编译器的光。

【讨论】:

    【解决方案9】:

    有点半开玩笑的回答;写声明

    array = initial_value
    

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

    【讨论】:

      【解决方案10】:

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

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

      【讨论】:

        【解决方案11】:

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

        如果您的编译器支持fold expressions,您可以使用模板魔术和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
        

        您可以查看code at work(在 Wandbox)

        【讨论】:

          【解决方案12】:

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

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

          【讨论】:

            【解决方案13】:

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

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

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

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

            【讨论】:

            • 对不起,这不是真的。也许您在测试期间忘记打开编译优化(使用调试模式进行测试?)。如果我对此进行测试,循环几乎总是比 memfill 快 50%(“总是”,因为我的机器上有一些负载抖动)。并使用 memset(a,0,sizeof(a));甚至比循环填充快两倍。
            • 与任何基准测试代码一样,您需要非常小心。添加一个循环来执行计时代码 10 次(并将数组的大小增加一倍至 20M)显示——对我来说,在 MacBook Pro 上运行 macOS Sierra 10.12.3 并使用 GCC 6.3.0——这是第一次,使用循环大约需要 4600 µs,而 memfill() 代码大约需要 1200 µs。然而,在随后的迭代中,循环大约需要 900-1000 µs,而 memfill() 代码需要 1000-1300 µs。第一次迭代可能会受到填充缓存时间的影响。逆向测试,memfill() 第一次很慢。
            【解决方案14】:
            1. 如果您的数组声明为静态数组或全局数组,则所有元素 在数组中已经有默认的默认值 0。
            2. 某些编译器在调试模式下将数组的默认值设置为 0。
            3. 很容易将默认设置为 0 : 整数数组[10] = {0};
            4. 但是,对于其他值,您可以使用 memset() 或循环;

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

            【讨论】:

              【解决方案15】:

              int 数组[1024] = {[0 ... 1023] = 5};由于上述工作正常,但请确保...点之间没有空格

              【讨论】:

              • 发布代码时使用格式:stackoverflow.com/editing-help
              • 我被int myArray[10] = { 0 }弄糊涂了。我虽然它可以应用于任何其他常量。但它没有。您的解决方案会有所帮助。
              【解决方案16】:

              没有人提到访问初始化数组元素的索引顺序。我的示例代码会给它一个说明性的例子。

              #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
              

              【讨论】:

              • &lt;iostream&gt; 无效C 因为std::coutstd::cin 等是std::namespace 的一部分,而C 不支持namespaces。尝试使用 &lt;stdio.h&gt; 代替 printf(...)
              【解决方案17】:

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

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

              额外的好处:代码实际上是清晰的:)

              【讨论】:

              • 专门要求初始化的问题。这显然不是初始化,而是在 初始化之后完成的赋值。它可能会立即完成,但它仍然不是初始化。
              • 对于多次调用的函数内的大型静态查找表完全没有帮助。
              • ...不要记得函数内部的静态查找表是原始问题的一部分 - 保持简单。也就是说,@Community 可能成功了。
              【解决方案18】:

              我知道用户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 尝试此代码。

              【讨论】:

                【解决方案19】:

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

                int a[4];
                
                unsigned int size = sizeof(a) / sizeof(a[0]);
                for (unsigned int i = 0; i < size; i++)
                  a[i] = 0;
                

                【讨论】:

                  【解决方案20】:

                  如果事先知道数组的大小,可以使用 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)
                  

                  【讨论】:

                    【解决方案21】:
                    #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 ...... 直到整个数组的大小

                    【讨论】:

                      【解决方案22】:

                      方法一:

                      int a[5] = {3,3,3,3,3}; 
                      

                      形式初始化技术。

                      方法二:

                      int a[100] = {0};
                      

                      但值得注意的是

                      int a[10] = {1}; 
                      

                      不会将所有值初始化为 1

                      这种初始化方式只针对0

                      如果你这样做

                      int a[100];
                      

                      一些编译器倾向于采用垃圾值,因此总是首选这样做

                      int a[1000] = {0};
                      

                      【讨论】:

                        【解决方案23】:

                        用零初始化 -

                          char arr[1000] = { 0 };
                        

                        最好用正常的“for循环”来初始化,而不是0。

                          char arr[1000];
                          for(int i=0; i<arr.size(); i++){
                             arr[i] = 'A';
                          }
                        

                        【讨论】:

                          【解决方案24】:

                          就像 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);                                       
                          }
                          

                          你可以在here看到它。

                          【讨论】:

                            【解决方案25】:

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

                            #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

                            【讨论】:

                            • 我怀疑这是否是一个解决方案。我不确定sizeof(void) 是否有效。
                            • 它不起作用。只有前两个被初始化,其余的都是未初始化的。我在 Mac OS X 10.4 上使用 GCC 4.0。
                            • 这会调用未定义的行为,因为第二个memcpy() 中的源数据与目标空间重叠。使用memcpy() 的简单实现,它可能会工作,但不需要系统让它工作。
                            【解决方案26】:

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

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

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

                            【讨论】:

                            • 这不会可靠地工作。恕我直言,标准应该提供类似于memcpy 的功能,但在重叠的情况下指定了自下而上或自上而下的复制顺序,但事实并非如此。
                            • 正如我所说,我们所做的只是无法可靠地工作,但那时,我们更关注效率而不是避免未记录的功能。虽然向前复制内存更有效,但规范中没有说它不能以随机顺序向后复制或将其拆分到多个线程中。 memmove() 提供了无冲突复制的能力。
                            • 这相当于另一个answer 中的代码——并且有缺陷。使用 memmove() 并不能正常工作。
                            猜你喜欢
                            • 1970-01-01
                            • 2014-07-23
                            • 2016-12-09
                            • 2020-09-29
                            • 1970-01-01
                            • 2018-03-17
                            • 1970-01-01
                            • 1970-01-01
                            • 2019-07-02
                            相关资源
                            最近更新 更多