36

Does anyone have a way to initialize an array of ints (any multi-byte type is fine really), to a non-zero and non -1 value simply? By which I mean, is there a way to do this in a one liner, without having to do each element individually:

int arr[30] = {1, 1, 1, 1, ...}; // that works, but takes too long to type

int arr[30] = {1}; // nope, that gives 1, 0, 0, 0, ...

int arr[30];
memset(arr, 1, sizeof(arr)); // That doesn't work correctly for arrays with multi-byte
                             //   types such as int

Just FYI, using memset() in this way on static arrays gives:

arr[0] = 0x01010101
arr[1] = 0x01010101
arr[2] = 0x01010101

The other option:

for(count = 0; count < 30; count++)
   arr[count] = 1;    // Yup, that does it, but it's two lines.

Anyone have other ideas? As long as it's C code, no limits on the solution. (other libs are fine)

Mike
  • 47,263
  • 29
  • 113
  • 177
  • there's wmemset() for "wide" char arrays – Marc B Nov 20 '12 at 16:10
  • wouldn't other libs require >1 line? `#include libother` – mcalex Nov 20 '12 at 16:12
  • @MarcB - Not bad... two minor issues, first I understand `wchar_t is compiler-specific and can be as small as 8 bits` so that could be single byte. Second, I was hoping for something that could work on different types. But not a bad suggestion. Thanks. – Mike Nov 20 '12 at 16:18
  • Mac OS X has `memset_pattern4()`, `memset_pattern8()` and `memset_pattern16()` since version 10.5. – Pascal Cuoq Nov 20 '12 at 16:19
  • 1
    @mcalex - Touché. Ok, how about "1 liner per setting", we won't count `#includes` or more options to `gcc` – Mike Nov 20 '12 at 16:19
  • memset() "That doesn't work correctly for multi-byte arrays". Where did you get that idea from? Didn't you learn anything from [this (very good) question](http://stackoverflow.com/questions/12462615/how-do-i-correctly-set-up-access-and-free-a-multidimensional-array-in-c)? I even replied to you in a comment there: "please don't use the pointer-to-pointer syntax, it creates segmented multi-dim. arrays that are not compatible with... "memcpy, memset". – Lundin Nov 20 '12 at 16:25
  • @Lundin - See my edit, That's what I mean about using `memset()` doesn't work right. I want `1`, ie `00000001`, that's not what I'm getting. I'm sure there's an obvious reason but it seems to only set a `byte` value – Mike Nov 20 '12 at 16:39
  • @Mike in that case, write a for loop in a method that takes an 'arraySize' int in another class and just include that – mcalex Nov 20 '12 at 16:40
  • I think you mean multi-byte *values* – iabdalkader Nov 20 '12 at 16:41
  • @PascalCuoq - if only I had a Mac! I only have Windows and Linux, I'll give to try my wife's macbook when I get home. Thanks for the input! – Mike Nov 20 '12 at 17:40
  • @DarrelHoffman - Kinda... but see my comment to MarcB up the chain, I'm looking for a more generic solution, `memset32` or `memset64` forces my hand based on underlying architecture. – Mike Nov 20 '12 at 18:56
  • A bit of modification could make that function more generic. You'd just have to pass it the size of your data type. Or it could possibly figure it out on its own using something like `sizeof(arr[0])`. I'd have to play around with it to see how hard that'd be, but I think it could work. – Darrel Hoffman Nov 20 '12 at 21:47
  • @Mike Alright, now I understand the issue :) It has nothing to do with fragmented arrays as I thought, but with the issue of memset() only working on byte level. Anyway, the fastest and most generic solution is to use a number of pre-defined macros, to build up your own custom initializer list. See my answer below. – Lundin Nov 21 '12 at 15:26

7 Answers7

41

This is a GCC extension:

int a[100] = {[0 ... 99] = 1};
P.P
  • 117,907
  • 20
  • 175
  • 238
iabdalkader
  • 17,009
  • 4
  • 47
  • 74
  • That is awesome, I was not aware of the syntax. +1 – Mike Nov 20 '12 at 19:00
  • 7
    Note to anyone else using this, there's white space between the digits and the `...` which is important – Mike Nov 20 '12 at 19:04
  • @Mike check the link, you can also initialize multiple ranges and single elements. – iabdalkader Nov 20 '12 at 19:23
  • Correct me if I'm wrong, but designated initializers in the C language are: `typedef struct { int x; int y} type;` then `type t = { .x=1, .y=2 };` I have never seen the .. notation nor heard it referred to as designated initializer. I believe this is some GCC extension beyond standard C designated initializers. – Lundin Nov 21 '12 at 07:49
  • @Lundin it is a GCC extension, like I mentioned, and it's described in the link under *Designated Initializers* section. my answer was edited, I'm not sure what it's called but I think maybe "range initializer" is more appropriate ? – iabdalkader Nov 21 '12 at 07:57
  • @mux Apologies for editing your answer. I rolled it back to the original version. – P.P Oct 19 '13 at 17:26
  • 1
    Can this be extended to multi-dimensional arrays? – Abhishek Bhagate Jun 24 '21 at 08:53
  • @AbhishekBhagate yes, you simply add another set of brackets – Cheetaiean Mar 06 '23 at 22:30
26
for (count = 0; count < 30; count++) arr[count] = 1;

One line. :)

Art
  • 19,807
  • 1
  • 34
  • 60
  • 5
    `One line. :)` very true... the letter of the law was followed with this solution – Mike Nov 20 '12 at 17:29
22

You said something about 2 lines but you can do it in one line using comma ,operator.

for(count = 0; count < 30 ; arr[count] = 1,count++);
Omkant
  • 9,018
  • 8
  • 39
  • 59
  • I actually like this solution, the `,` operator is so unused. – Mike Nov 20 '12 at 17:30
  • which comma , operator is so unused ? I didn't get you . – Omkant Nov 20 '12 at 17:35
  • I have checked this code , its running without any error and warnings . You just copy this code and try the same, It should work because it's also behaviour of for loop – Omkant Nov 20 '12 at 17:37
  • 1
    I'll rephrase, "I like this solution because it uses the comma operator, and people don't use that enough" – Mike Nov 20 '12 at 17:48
  • 9
    Alternatively: `for(count = 0; count < 30; arr[count++] = 1);` – hammar Nov 21 '12 at 05:27
  • 4
    You can also write your whole C program on one single line. If someone could provide a rationale over how that makes sense, I'd be glad to hear it. – Lundin Nov 21 '12 at 12:30
20

The only sensible way to do this during initialization (rather than runtime) seems to be:

#define ONE1     1
#define FIVE1    ONE1, ONE1, ONE1, ONE1, ONE1
#define TEN1     FIVE1, FIVE1
#define TWENTY1  TEN1, TEN1
#define FIFTY1   TWENTY1, TWENTY1, TEN1
#define HUNDRED1 FIFTY1, FIFTY1

int array [100][4] =
{
  HUNDRED1,
  HUNDRED1,
  HUNDRED1,
  HUNDRED1
};

And next, #define ONE2 2 and so on. You get the idea.

EDIT : The reason why I wrote so many macros was to demonstrate how flexible this solution is. For this particular case you don't need all of them. But with macros like these you can write any kind of initializer list in a quick and flexible way:

{
  FIFTY1, FIFTY2,  // 1,1,1,1... 50 times, then 2,2,2,2... 50 times
  TWENTY3, EIGHTY4 // 3,3,3,3... 20 times, then 4,4,4,4... 80 times
  ... // and so on
};
Lundin
  • 195,001
  • 40
  • 254
  • 396
  • 2
    Very neat solution, readable and extendable and compile-time! – M. Mimpen Feb 28 '14 at 13:04
  • @Lundin: This is by far the best, smart and readable. Thanks! – WedaPashi Apr 02 '18 at 11:28
  • Could you generalize this a little to functions taking the number to be repeated? i.e. `#define ONE(n) 1`, then `#define FIVE(n) ONE(n), ONE(n), ONE(n), ONE(n), ONE(n)`, etc, so you don't need a separate set of macros for every number? – Nic Jul 18 '18 at 08:11
  • Actually, with a little clever trickery you could probably even generalize it to a function `#define REPEAT(symbol, count)`, though I'm too tired to figure out how that would work at the moment :) – Nic Jul 18 '18 at 08:12
  • @NicHartley Indeed, you can use this method to create more elegant macros. `#define FIVE(n)` does indeed look prettier than `FIVE1`. – Lundin Aug 06 '18 at 09:09
12

In C you typically develop your own "support library" with macros like

#define SET_ALL(a_, n_, v_)\
  do { size_t i, n = (n_); for (i = 0; i < n; ++i) (a_)[i] = (v_); } while(0)

#define SET_ALL_A(a_, v_) SET_ALL(a_, sizeof(a_) / sizeof *(a_), v_)
#define ZERO_ALL(a_, n_) SET_ALL(a_, n_, 0)
#define ZERO_ALL_A(a_) SET_ALL_A(a_, 0)

and then use them in your code as

int arr[30];

SET_ALL_A(arr, 1);
AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
  • That's actually a really going point, why I didn't think of including just a macro to take care of it is beyond me... – Mike Nov 20 '12 at 17:24
  • If you make an icky macro like this, why not write one to actually _initialize_ the array, rather than setting it in runtime like this? Suppose "arr" has static storage duration and you want to take advantage of the special initialization rules for such variables (they are initialized before main is called). – Lundin Nov 21 '12 at 12:27
  • @Lundin: If I were aware of any C feature that would allow me to *initialize* the array as requested, I'd use it. But alas I have no idea how to do it. I see the "icky macro" above as the best thing available in C. If you can suggest anything better, I'm all ears. – AnT stands with Russia Nov 21 '12 at 16:01
8

One line with pointers!

for (int *p = a; p < (a + 30); p++) *p = 1;

Or if you're prematurely afraid of performance hit caused by repeatedly calculating (a + 30):

for (int *p = a + 30 - 1; p >= a; p--) *p = 1;
Archie
  • 6,391
  • 4
  • 36
  • 44
Bartosz Ciechanowski
  • 10,293
  • 5
  • 45
  • 60
  • 1
    If you want to be sure that `a + 30` will only be calculated once, I would do `for (int *p = a, *pEnd = a + 30; p < pEnd; p++) *p = 1;`. Your second for loop invokes undefined behaviour, because it calculates `a - 1`, which is out of bounds. `p` does not point to the array `a`, so `p >= a` is undefined. – mch Sep 21 '17 at 08:00
2

For initialization to a static value, I have generally considered typing it out to be preferred, as in:

int arr[30] = {1, 1, 1, 1, ...}; 

In this case, the compiler can (and usually does) spit out optimized initialization in preamble code.

Sometimes the initialization is more dynamic, as in this example:

int arr[30];
int x = fetchSomeValue();
for(int i=0; i<30; i++) arr[i] = x;

In these cases you have to code it and the general rule is to maximize readability, not minimize typing. This code will be written once and read a multitude of times.

CuriousRabbit
  • 2,124
  • 14
  • 13