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

I have a large array in C (not C++ if that makes a difference). I want to initialize all members to the same value. I could swear I once knew a simple way to do this. I could use memset() in my case, but isn't there a way to do this that is built right into the C syntax?

转载于:https://stackoverflow.com/questions/201101/how-to-initialize-all-members-of-an-array-to-the-same-value

weixin_41568196
撒拉嘿哟木头 memset() specific discussion: stackoverflow.com/questions/7202411/… I think it only works for 0.
4 年多之前 回复
csdnceshi54
hurriedly% memset() can help, but depends of the value.
5 年多之前 回复
csdnceshi72
谁还没个明天 Actually abelenky's answer is using designated initializer, but isn't fully formed initialising code
6 年多之前 回复
csdnceshi53
Lotus@ None of the answers so far mentions the designated initializer notation that is feasible with C99 and above. For example: enum { HYDROGEN = 1, HELIUM = 2, CARBON = 6, NEON = 10, … }; and struct element { char name[15]; char symbol[3]; } elements[] = { [NEON] = { "Neon", "Ne" }, [HELIUM] = { "Helium", "He" }, [HYDROGEN] = { "Hydrogen", "H" }, [CARBON] = { "Carbon", "C" }, … };. If you remove the ellipsis …, those fragments do compile under C99 or C11.
6 年多之前 回复

19个回答

Unless that value is 0 (in which case you can omit some part of the initializer and the corresponding elements will be initialized to 0), there's no easy way.

Don't overlook the obvious solution, though:

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

Elements with missing values will be initialized to 0:

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

So this will initialize all elements to 0:

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

In C++, an empty initialization list will also initialize every element to 0. This is not allowed with C:

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

Remember that objects with static storage duration will initialize to 0 if no initializer is specified:

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

And that "0" doesn't necessarily mean "all-bits-zero", so using the above is better and more portable than memset(). (Floating point values will be initialized to +0, pointers to null value, etc.)

csdnceshi52
妄徒之命 int myArray[10] = { 0 }; // all elements 0 is not true for c++. int myArray[10] = { 5 }; It will only assign to the first element.
大约 2 年之前 回复
csdnceshi54
hurriedly% In other news, apparently you cannot use a variable as the size if you want to initialize it on the same line.
5 年多之前 回复
csdnceshi50
三生石@ Can somebody prove this statement using the C Standard? Is it already included in C90? "Unless that value is 0 (in which case you can omit some part of the initializer and the corresponding elements will be initialized to 0)"
接近 6 年之前 回复
csdnceshi62
csdnceshi62 Check out qrdl's answer just below. It's a GCC extension.
7 年多之前 回复
weixin_41568183
零零乙 I don't think I've seen this yet: int myArray[] = {[3] = 123, [7] = 23}; Gives you {0, 0, 0, 123, 0, 0, 0, 23}
7 年多之前 回复
csdnceshi70
笑故挽风 Oh obviously I was parsing the answer from below scrolling up the page and considered the = { x }; assignment in isolation from the context of the preceding text o_O which made me lost. I am sorry for cluttering up the comments section ^_^". I will try to go fully context-aware on my reading SO answers from this day on to avoid shaming myself like this again.
7 年多之前 回复
csdnceshi53
Lotus@ You're the only one that claimed, in that comment, that all elements would be set to -1. This answer claims, rightly, that all unspecified elements get set to zero. The results of your code is in accord with this claim.
7 年多之前 回复
csdnceshi70
笑故挽风 Do you see the comment in int myArray[10] = { 0 }; //all elements 0 from the answer? Well when I use -1 instead, it is only the first element that is set to -1 and not all as claimed. The codepad link has a snippet of code to prove the that it is wrong to suggest the = { x }; assignment truly sets all elements to x. I want others to see that.
7 年多之前 回复
csdnceshi53
Lotus@ What do you mean it doesn't work? It does exactly what this answer says it should do. It doesn't do what the comment in your code says, but that comment is wrong.
7 年多之前 回复
csdnceshi70
笑故挽风 int myArray[10] = { -1 }; just does not work though, see codepad.org/ckuy54OZ!!
7 年多之前 回复
csdnceshi58
Didn"t forge can we use the same technique to initialize a 2 D array allocated on heap using malloc(sizeof(int [ROW][COL])). Thanks
7 年多之前 回复
csdnceshi62
csdnceshi62 Though of course you should be asking whether std::vector<int>(10) does zero-initialization, instead.
大约 8 年之前 回复
csdnceshi62
csdnceshi62 That will call the default constructor, which, once you get past the argument of whether there actually is a constructor for primitive types, should do zero-initialization as well.
大约 8 年之前 回复
csdnceshi66
必承其重 | 欲带皇冠 What about float * = new float[10]; will this initialize to zero as well?
大约 8 年之前 回复
weixin_41568174
from.. C99 has a lot of nice features for structure and array initialization; the one feature it does not have (but Fortran IV, 1966, had) is a way to repeat a particular initializer for an array.
大约 12 年之前 回复
weixin_41568174
from.. Looking at section 6.7.8 Initialization of the C99 standard, it does not appear that an empty initializer list is allowed.
大约 12 年之前 回复
weixin_41568184
叼花硬汉 Reading through the C++ standard, you can also do int array[10] = {}; to zero initialise. I don't have the C standard to check this is valid C as well though.
大约 12 年之前 回复

If your compiler is GCC you can use following syntax:

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

Check out detailed description: http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Designated-Inits.html

csdnceshi57
perhaps? This syntax apparently does not work with g++ / C++.
3 年多之前 回复
csdnceshi54
hurriedly% I thought when you say gcc it also applies in g++.
接近 7 年之前 回复
csdnceshi74
7*4 or for a 2d array, bool array[][COLS] = { [0...ROWS-1][0...COLS-1] = true}, though I'm not certain that's more readable than the full form.
7 年多之前 回复
csdnceshi63
elliott.david better yet: "int array[] = {[0 ... 1023] = 5}", the size of array will automatically be set to 1024, easier and safer to modify.
7 年多之前 回复
csdnceshi71
Memor.の Why should I? It is a standard compiler behaviour, not specific for designated initialisers. If you statically initialise 65536 ints, like int foo1 = 1, foo2 = 1, ..., foo65536 =1; you will get the same size increase.
7 年多之前 回复
csdnceshi58
Didn"t forge why don't you mention it in your answer?
7 年多之前 回复
csdnceshi71
Memor.の Compiler has to add 65536 ints into static data, which is 256 K - exactly the size increase you've observed.
7 年多之前 回复
csdnceshi58
Didn"t forge And that syntax causes a huge increase in the file size of compiled binaries. For N = 65536 (instead of 1024), my binary jumps from 15 KB to 270 KB in size!!
7 年多之前 回复
weixin_41568208
北城已荒凉 thanks for the response.. so basically for dynamic allocation i can't use this technique. correct?
7 年多之前 回复
csdnceshi71
Memor.の What you are trying to do isn't an initialisation but assignment, this syntax cannot be used in such situation, you will be better off using memset()
7 年多之前 回复
weixin_41568208
北城已荒凉 I tried initializing a 2D array dynamically allocated on heap using malloc(sizeof(int [row][col])) and got compile time error on line where is used this line : arr[row][col] = {[0 ... row -1] [0 ... col-1] = -1}; The error i got was "expected expression before '{' token" Any idea on this? Thanks
7 年多之前 回复

For statically initializing a large array with the same value, without multiple copy-paste, you can use macros:

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

If you need to change the value, you have to do the replacement at only one place.

Edit: possible useful extensions

(courtesy of Jonathan Leffler)

You can easily generalize this with:

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

A variant can be created using:

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

that works with structures or compound arrays.

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

macro names are negotiable.

csdnceshi51
旧行李 Have at it! :D — Yes, by all means use it.
3 年多之前 回复
weixin_41568183
零零乙 That is a great extension! Do you mind if I add it to my answer?
3 年多之前 回复
csdnceshi51
旧行李 You can easily generalize this with #define VAL_1(X) X and #define VAL_2(X) VAL_1(X), VAL_1(X), etc. A variant can be created using #define STRUCTVAL_1(...) { __VA_ARGS__ } and #define STRUCTVAL_2(...) STRUCTVAL_1(__VA_ARGS__), STRUCTVAL_1(__VA_ARGS__), etc that works with structures or compound arrays. #define STRUCTVAL_48(...) STRUCTVAL_32(__VA_ARGS__), STRUCTVAL_16(__VA_ARGS__) and struct Pair { char key[16]; char val[32]; }; and struct Pair p_data[] = { STRUCTVAL_48("Key", "Value") }; and int a_data[][4] = { STRUCTVAL_48(12, 19, 23, 37) }; — macro names negotiable.
3 年多之前 回复
weixin_41568184
叼花硬汉 "VAL_64X is... defined somewhere... 42. Wait? What is this supposed to do?" If we ever work together, please just use a few extra lines of code, and dumb them down enough so that someone like me can understand :)
6 年多之前 回复
weixin_41568131
10.24 - question: Is the array index included for a reason in your example? i.e. in my ANSI C compiler int myArray[] = { VAL_32X, VAL_16X, VAL_4X, VAL_1X }; works just fine. I am just not sure if there is a subtle disadvantage for not using an explicit index value. +1 for your answer.
大约 7 年之前 回复
csdnceshi56
lrony* Keep in mind that you can use this method also if VAL_1X isn't a single integer but a list. Like Amigable states, this is also the way to go for embedded systems where you want to define the init values of a EEPROM or Flash memory. In both cases you can't use memset().
7 年多之前 回复
weixin_41568126
乱世@小熊 (Unless the flash is used as a regular filesystem in say, Linux or Windows, in which case the flash is used in the same way a hard drive would.) @Alcott.
8 年多之前 回复
weixin_41568126
乱世@小熊 on old computers and still on many embedded systems, the code is eventually placed in an EPROM or ROM. ROM-able has also come to mean, in embedded systems, "code put in flash", because it has about the same implications, namely that the memory can not be written runtime. I.e. memset or any other instruction to update or change memory can not be used. Constants, though, can be expressed and flashed or ROM-ed before the program starts.
8 年多之前 回复
csdnceshi55
~Onlooker what did you mean by "ROM-able"?
8 年多之前 回复
weixin_41568174
from.. memset initializes with a char. It can't be used to init an int array to a value like 42.. The value 0 can be used to init to zero. the value -1 can be used to init the array to -1.
9 年多之前 回复
csdnceshi52
妄徒之命 Preprocessor will actually generate the code from #defines. With larger array dimensions the executable size will grow. But definitely + for the idea ;)
大约 10 年之前 回复
weixin_41568126
乱世@小熊 If the data must be ROM-able, memset can not be used.
10 年多之前 回复
weixin_41568183
零零乙 Of course memset() is the way to go. I understood that OP was looking for an alternative.
大约 11 年之前 回复
csdnceshi61
derek5. I would only consider this in extreme cases, surely a memset is the more elegant way to express it.
大约 11 年之前 回复

There is a fast way to initialize array of any type with given value. It works very well with large arrays. Algorithm is as follows:

  • initialize first element of the array (usual way)
  • copy part which has been set into part which has not been set, doubling the size with each next copy operation

For 1 000 000 elements int array it is 4 times faster than regular loop initialization (i5, 2 cores, 2.3 GHz, 4GiB memory, 64 bits):

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;
}
csdnceshi71
Memor.の As with any benchmarking code, you need to be extremely careful. Adding a loop to execute the timing code 10 times (and doubling the size of the array to 20M) shows — for me, running on a MacBook Pro with macOS Sierra 10.12.3 and using GCC 6.3.0 — that the first time, using the loop takes around 4600 µs, while the memfill() code takes around 1200 µs. However, on subsequent iterations, the loop takes about 900-1000 µs while the memfill() code takes 1000-1300 µs. The first iteration is probably impacted by the time to fill the cache. Reverse the tests and memfill() is slow first time.
3 年多之前 回复
csdnceshi64
游.程 Sorry, but this is not true. Maybe you forgot to turn on compile optimization during your tests (tested with debug mode?). If I test this, the loop is nearly always 50% faster than memfill ('always' due to some load jitters on my machine). And using memset(a,0,sizeof(a)); is even twice as fast than loopfill.
4 年多之前 回复

I saw some code that used this syntax:

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

Where it becomes particularly useful is if you're making an array that uses enums as the index:

enum
{
    ERR_OK,
    ERR_FAIL,
    ERR_MEMORY
};

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

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

This keeps things in order, even if you happen to write some of the enum-values out of order.

More about this technique can be found here and here.

csdnceshi65
larry*wei This is C99 initializer syntax, already covered by some of the other answers. You could usefully make the declaration into char const *array[] = { ... }; or even char const * const array[] = { ... };, couldn't you?
8 年多之前 回复

Nobody has mentioned the index order to access the elements of the initialized array. My example code will give an illustrative example to it.

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

The output is:

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
weixin_41568131
10.24 <iostream> isn't valid C as std::cout, std::cin, etc is part of the std::namespace and C doesn't support namespaces. Try using <stdio.h> for printf(...) instead.
2 年多之前 回复
csdnceshi51
旧行李 Posting C++ code to a C post questions is applicability. Suggest re-working to C.
大约 4 年之前 回复
  1. If your array is declared as static or is global, all the elements in the array already have default default value 0.
  2. Some compilers set array's the default to 0 in debug mode.
  3. It is easy to set default to 0 : int array[10] = {0};
  4. However, for other values, you have use memset() or loop;

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

For initializing 'normal' data types (like int arrays), you can use the bracket notation, but it will zero the values after the last if there is still space in the array:

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

If the array happens to be int or anything with the size of int or your mem-pattern's size fits exact times into an int (i.e. all zeroes or 0xA5A5A5A5), the best way is to use memset().

Otherwise call memcpy() in a loop moving the index.

If you want to ensure that every member of the array is explicitly initialized, just omit the dimension from the declaration:

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

The compiler will deduce the dimension from the initializer list. Unfortunately, for multidimensional arrays only the outermost dimension may be omitted:

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

is OK, but

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

is not.

weixin_41568134
MAO-EYE No — length inference has been in C since the days of pre-standard C (since K&R 1st Edition was published, and probably a while before that). Designated initializers were new in C99, but this isn't using designated initializers.
3 年多之前 回复
csdnceshi72
谁还没个明天 Both initializers and length inference were introduced in C99.
接近 7 年之前 回复
csdnceshi77
狐狸.fox No. You are omitting the innermost dimension, which is not allowed. This will give a compiler error.
8 年多之前 回复
csdnceshi78
程序go is this correct ? int myPoints[10][] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9} };
8 年多之前 回复
共19条数据 1 尾页
Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问
相关内容推荐