1

In my C++ program I am trying to initialize a 3*3*3 array of type double with all 0's. In the class header file, I declared a member

double list[3][3][3];

When I printed out the content of this array, I found that not all entries are 0 as I expected. e.g. list[1][1][1] has value 4.03158e-321

Hence I manually initialized this array to all 0's in the constructor:

list = {{{0,0,0},{0,0,0},{0,0,0}},
      {{0,0,0},{0,0,0},{0,0,0}},
      {{0,0,0},{0,0,0},{0,0,0}}};

This makes my program work, however, I got the compiler warning:

warning: extended initializer lists only available with -std=c++0x or -std=gnu++0x

My question is therefore

  1. Why does list have non-zero entries after being initialized in the header?
  2. Why do I get the above warning message, and how to get rid of it?

My compiler is g++ (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2, with gcc version 4.5.2 (Ubuntu/Linaro 4.5.2-8ubuntu4)

yang
  • 107
  • 1
  • 2
  • 7

5 Answers5

5

In C++03 you can only use that initialization when defining the array:

double list[3][3][3] = {{{0,0,0},{0,0,0},{0,0,0}},
                        {{0,0,0},{0,0,0},{0,0,0}},
                        {{0,0,0},{0,0,0},{0,0,0}}};

The compiler is warning that according to the current standard it should not accept your code, even if it is able to process it by applying the upcoming standard rules, where the {...} is called an external-initializer.

In this particular case, where the array is a member and you want to initialize it to all zeroes, you can just use value-initialization in C++0x:

struct test { 
   double list[3][3][3];
   test() : list()
   {}
};

For members of POD types (which an array of double is), the syntax above (list()) in the initializer list means that the member is to be value-initialized which effectively means that all values will be set to 0

David Rodríguez - dribeas
  • 192,922
  • 20
  • 275
  • 473
3

Am I missing something or can you not just do

class Class {
public:
    double array[3][3][3];

    Class() : array() { }
};
Seth Carnegie
  • 70,115
  • 19
  • 169
  • 239
2
  1. In the header it's not initialized, it's just declared. Builtin types (and more in general PODs) are not automatically zero-initialized if they aren't globals (actually, that have static storage duration) for performance reasons (as many things in C++, initialization is an opt-in, you pay for it only if you need it).

  2. That syntax is valid only when initializing an array, while that instruction is an assignment. That syntax, instead can be used in many more places in the new C++ standard (formerly C++0x, now C++11 since it has just been approved).

In my opinion, the quickest way to solve your problem is just to do:

double * firstElem=&list[0][0][0];
std::fill(firstElem, firstElem+27, 0.);

that treats list as a monodimensional array of 27 doubles and fills it with zeroes (more info about that trick here).

Notice that this argument is also treated briefly into the array FAQ.

Community
  • 1
  • 1
Matteo Italia
  • 115,256
  • 16
  • 181
  • 279
  • 1
    -1. Its wrong. You cannot use `std::fill` like this, to initialize 3D array. – Nawaz Aug 23 '11 at 17:03
  • @Nawaz: when posting the answer I forgot the cast, now I added it. – Matteo Italia Aug 23 '11 at 17:05
  • Even this its wrong. In fact, it is more dangerous now, as you will get any warning now. Its undefined-behaviour. – Nawaz Aug 23 '11 at 17:07
  • @Nawaz: that usage is straight from the FAQ from FredOverflow, I'm quite sure he did the research in the standard. Still, I'll have a quick look to make sure. – Matteo Italia Aug 23 '11 at 17:09
  • @Nawaz: Actually, it's not a simple cast, I remembered wrong, there's more in it (although I'm not sure it makes any difference). Now it should be ok. – Matteo Italia Aug 23 '11 at 17:10
  • FredOverflow didn't talk about 2D array and treating it like 1D array. – Nawaz Aug 23 '11 at 17:13
  • @Nawaz: http://stackoverflow.com/questions/4810664/how-do-i-use-arrays-in-c/4984228#4984228, the code block after the big grid; it should follow right from [dcl.array] ¶6-9. – Matteo Italia Aug 23 '11 at 17:15
  • @Matteo, although I prefer the current final code (`&list[0][0][0]`), I don't think that the previous one was UB. It is more *obscure* and fragile (forcing the cast means that if anything changes you are screwed), but the standard guarantees that `list` will decay to a pointer to the first element (type `double[3][3]`), and the cast will force that to be interpreted to a pointer to `double`, but the standard ensures that `(void*)&list == (void*)&list[0] == (void*)&list[0][0] == (void*)&list[0][0][0]`, so the net result is the same (just in a much better way) – David Rodríguez - dribeas Aug 23 '11 at 17:16
  • @David: I too thought that it wouldn't matter, still I changed it after re-looking at the FredOverflow FAQ, because I'm sure he did the research and I didn't want to spend half an hour rambling through the standard. :) – Matteo Italia Aug 23 '11 at 17:18
  • 1
    @David: Because its treating 3D array as 1D array, that means, `&firstElem[0] == &list[0][0][0]; &firstElem[1] == &list[0][0][1]; &firstElem[2] == &list[0][0][2]` but as far as I know, the Standard nowhere guarantees that `&firstElem[3] == &list[0][1][0]`. Also, see this topic : http://stackoverflow.com/questions/2036104/validity-of-the-code – Nawaz Aug 23 '11 at 17:26
  • 2
    @Nawaz: The standard guarantees that the contents of the array are in contiguous memory. It guarantees that `&list[1]` is right after `&list[0]` in memory, so yes, it does guarantee that: `(&list[0][0][0] + 4) == &list[0][1][0]` Note that they **are** all subobjects of the same object `list`. – David Rodríguez - dribeas Aug 23 '11 at 17:48
1

There's a simpler way to do it. The following should work in C or C++, just for initializing the variable (i.e. not in an assignment):

double list[3][3][3] = {0};

The {0} is a special initializer that sets pretty much any structure to all zeroes.

A. L. Flanagan
  • 1,076
  • 8
  • 18
  • Just to clarify a bit, the above declaration means "Set the first element to 0. Oh, and since I didn't specify them, set all the rest to zeroes also". I suppose you could use = {1} to set list[0][0][0] to 1, and make the rest zero, but it's not the clearest way to do that. :) – A. L. Flanagan Aug 23 '11 at 17:41
  • I guess it would work in the main(), but I couldn't use it in the header. i.e. I would got this error: a brace-enclosed initializer is not allowed here before ‘{’ token – yang Aug 23 '11 at 17:45
  • yeah, it only works where you can do an initialization. possibly static double list... would work. However, if you're doing C++, you should consider wrapping things in a class instead. Globally-scoped non-class data is just asking for trouble. – A. L. Flanagan Aug 26 '11 at 20:57
0

Why not set the values to zero with memset or loop ?

phoxis
  • 52,327
  • 12
  • 74
  • 110