4

i need a few explanation on array of pointers and more precisly, how to declare them.
Take a look at this code:

main()
{
    int array[] = {5, 4, 2};
    int array2[] = {6, 8};
    int* int_arrays[2] = {array, array2}; // It works!

//  int* int_arrays2[2] =
//  {
//      {5, 4, 2},
//      {6, 8}
//  };
//
    int i, j;
    for(i = 0; i < 2; i++) 
    {
        for(j = 0; j < 3; j++) // This loop print a garbage value at the end, no big deal.
                printf("%d\n", int_arrays[i][j]);
    }
}

For me the commented declartation means the same as the one above. But it doesn't work.
The visual studio C compiler give me those indications:
error: too many initializers.
warning: int* differs in levels of indirection from int.

I guess it means that int array[] = {5, 4, 2} is something valid to assign to an int*
while {5, 4, 2} is not.
Could you show me a way to delcare my array of pointer correctly?

aurelienC
  • 1,113
  • 3
  • 12
  • 22

3 Answers3

5

An array initializer is not a object and so you can't have a pointer to the start of such and object. If you have at least C99, you could do

int* int_arrays2[2] =
{
     (int[]){5, 4, 2},
     (int[]){6, 8}
};

These are so-called "compound literals" that are objects, and thus in this case covert to the pointer type that you need.

Jens Gustedt
  • 76,821
  • 6
  • 102
  • 177
  • It's funny because before posting my question the last thing i tried was to cast the arrays initializers to `(int *)` . I guess `(int [ ])` works because the initializer is converted to an array and then the `array[0]` is naturally equivalent to `*array` ? – aurelienC Dec 04 '15 at 13:07
  • @atm, yes, compound literals start in Section 5.4.4 or "Modern C" – Jens Gustedt Dec 04 '15 at 21:33
  • 1
    @aurelienC, yes these `{ a, b, c }` are array initializers so you need to first create an array and then this array "decays" to a pointer to the first element. – Jens Gustedt Dec 04 '15 at 21:35
3

The declaration

int* int_arrays[2]

declares the variable int_arrays to be an array of two pointers to int. And you initialize the array to contain two pointers to int in the "it works" code. Remember that arrays naturally decays to pointers to their first element, so for example an array of int can be used where int * is expected.

However, you can't use an array initializer list (like { 5, 4, 2}) as a pointer, because it's not. That's why the code you have commented out doesn't build. You could use an array of arrays instead when declaring it, because that's how you initialize it:

char int_array_of_arrays[2][3] = { ... };

An important not about the array of arrays, and the decaying of arrays to pointers: An array of arrays is not the same as a pointer to pointer.


As for the "garbage" problem, it's because you try to print the third element of an array containing only two elements. C doesn't have any bounds checking, if you try to index an array out of bounds you will have undefined behavior.

Community
  • 1
  • 1
Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • **Remember that arrays naturally decays to pointers to their first element** bravo, that's awesome @JoachimPileborg +1 – Cherubim Dec 04 '15 at 12:06
  • @ch3rub7; Not always. I think Joachim should have mention this in his answer. – haccks Dec 04 '15 at 12:07
  • The thing with the array of arrays is that all arrays have the same length, i guess i can fill the smaller arrays with null values...but anyway it was just a theorical question. "you can't use an array initializer list (like { 5, 4, 2}) as a pointer, because it's not" clarified my problem, thanks! – aurelienC Dec 04 '15 at 12:54
2

Consider the first declaration

int* int_arrays[2] = {array, array2}; 

Here is the initilaizer list contains two expressions that represent array names. Arrays used in expressions are implicitly converted to pointers to their first elements.

In fact this declaration is equivalent to the following

int* int_arrays[2] = { &array[0], &array2[0] };

Take into account that int_arrays is declared as an array with two elements and consequently two initializers are used to initialize the elements of the array.

You can use initializer list with more than one initializer to initialize aggregates: arrays and structure.

If you are using a scalar value than the corresponding initializer list may have only one initializer. Consider

int x = { 10 };  // Okey
int y = ( 10, 20 }; // compiler error

Now consider this declaration

int* int_arrays2[2] =
{
      {5, 4, 2},
      {6, 8}
};

In this declaration the array int_arrays2 as before contains only two elements. Each element of the array is a scalar object of type int *. The initialization avove semantically equivalent to the following

int *p1 = {5, 4, 2};
int *p2 = {6, 8};

where p1 and p2 correspond to int_arrays2[0] and int_arrays2[1].

They are scalar objects and as it has been pointed out above may be initialized only by an initializer list with one initializer.

So the compiler issues an error.

On the other hand instead of this wrong declaration you could write

int* int_arrays2[2] =
{
      ( int[] ){5, 4, 2},
      ( int [] ){6, 8}
};

Here is used so-called compound literals that create unnamed arrays of the specified types. So in the left side there is an array of two elements and in the right side there is an initializer list with two initializers, compound literals, that are converted to pointers to the first elements of the created unnamed arrays.

Such an initialization is correct.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335