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

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 年多之前 回复
weixin_41568208
北城已荒凉 memset() can help, but depends of the value.
5 年多之前 回复
csdnceshi57
perhaps? Actually abelenky's answer is using designated initializer, but isn't fully formed initialising code
6 年多之前 回复
csdnceshi74
7*4 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.)

csdnceshi55
~Onlooker 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 年之前 回复
csdnceshi76
斗士狗 Could you potentially create a macro to repeat 5, the necessary number of times?
接近 4 年之前 回复
csdnceshi71
Memor.の In other news, apparently you cannot use a variable as the size if you want to initialize it on the same line.
5 年多之前 回复
weixin_41568184
叼花硬汉 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 年之前 回复
csdnceshi77
狐狸.fox Check out qrdl's answer just below. It's a GCC extension.
7 年多之前 回复
csdnceshi69
YaoRaoLov 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 年多之前 回复
csdnceshi59
ℙℕℤℝ 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 年多之前 回复
csdnceshi58
Didn"t forge 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 年多之前 回复
csdnceshi59
ℙℕℤℝ 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 年多之前 回复
csdnceshi58
Didn"t forge 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 年多之前 回复
csdnceshi59
ℙℕℤℝ int myArray[10] = { -1 }; just does not work though, see codepad.org/ckuy54OZ!!
7 年多之前 回复
csdnceshi64
游.程 can we use the same technique to initialize a 2 D array allocated on heap using malloc(sizeof(int [ROW][COL])). Thanks
7 年多之前 回复
csdnceshi77
狐狸.fox Though of course you should be asking whether std::vector<int>(10) does zero-initialization, instead.
大约 8 年之前 回复
csdnceshi77
狐狸.fox 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 年之前 回复
csdnceshi54
hurriedly% What about float * = new float[10]; will this initialize to zero as well?
大约 8 年之前 回复
csdnceshi72
谁还没个明天 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 年之前 回复
csdnceshi72
谁还没个明天 Looking at section 6.7.8 Initialization of the C99 standard, it does not appear that an empty initializer list is allowed.
大约 12 年之前 回复
weixin_41568196
撒拉嘿哟木头 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

csdnceshi56
lrony* This syntax apparently does not work with g++ / C++.
3 年多之前 回复
csdnceshi59
ℙℕℤℝ I thought when you say gcc it also applies in g++.
接近 7 年之前 回复
csdnceshi79
python小菜 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 年多之前 回复
csdnceshi60
℡Wang Yan better yet: "int array[] = {[0 ... 1023] = 5}", the size of array will automatically be set to 1024, easier and safer to modify.
7 年多之前 回复
csdnceshi67
bug^君 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 年多之前 回复
csdnceshi76
斗士狗 why don't you mention it in your answer?
7 年多之前 回复
csdnceshi67
bug^君 Compiler has to add 65536 ints into static data, which is 256 K - exactly the size increase you've observed.
7 年多之前 回复
csdnceshi76
斗士狗 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 年多之前 回复
csdnceshi54
hurriedly% thanks for the response.. so basically for dynamic allocation i can't use this technique. correct?
7 年多之前 回复
csdnceshi67
bug^君 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 年多之前 回复
csdnceshi54
hurriedly% 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.

csdnceshi67
bug^君 Have at it! :D — Yes, by all means use it.
3 年多之前 回复
csdnceshi64
游.程 That is a great extension! Do you mind if I add it to my answer?
3 年多之前 回复
csdnceshi67
bug^君 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 年多之前 回复
csdnceshi66
必承其重 | 欲带皇冠 "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 年多之前 回复
csdnceshi51
旧行李 - 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 年之前 回复
csdnceshi77
狐狸.fox 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 年多之前 回复
csdnceshi70
笑故挽风 (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 年多之前 回复
csdnceshi70
笑故挽风 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 年多之前 回复
weixin_41568184
叼花硬汉 what did you mean by "ROM-able"?
8 年多之前 回复
weixin_41568134
MAO-EYE 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 年之前 回复
csdnceshi70
笑故挽风 If the data must be ROM-able, memset can not be used.
10 年多之前 回复
csdnceshi64
游.程 Of course memset() is the way to go. I understood that OP was looking for an alternative.
大约 11 年之前 回复
csdnceshi68
local-host 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;
}
csdnceshi61
derek5. 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 年多之前 回复
weixin_41568208
北城已荒凉 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 年多之前 回复

Here is another way:

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

See:

C-Extensions

Designated inits

Then ask the question: When can one use C extensions?

The code sample above is in an embedded system and will never see the light from another compiler.

A slightly tongue-in-cheek answer; write the statement

array = initial_value

in your favourite array-capable language (mine is Fortran, but there are many others), and link it to your C code. You'd probably want to wrap it up to be an external function.

You can do the whole static initializer thing as detailed above, but it can be a real bummer when your array size changes (when your array embiggens, if you don't add the appropriate extra initializers you get garbage).

memset gives you a runtime hit for doing the work, but no code size hit done right is immune to array size changes. I would use this solution in nearly all cases when the array was larger than, say, a few dozen elements.

If it was really important that the array was statically declared, I'd write a program to write the program for me and make it part of the build process.

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.

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

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.

csdnceshi63
elliott.david 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 年多之前 回复
csdnceshi76
斗士狗 Both initializers and length inference were introduced in C99.
接近 7 年之前 回复
csdnceshi55
~Onlooker No. You are omitting the innermost dimension, which is not allowed. This will give a compiler error.
8 年多之前 回复
csdnceshi57
perhaps? is this correct ? int myPoints[10][] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9} };
8 年多之前 回复
共19条数据 1 尾页
Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问
相关内容推荐