hvaminion
hvaminion

Reputation: 145

How does ** work in a 2 dimensional array?

int main(void) {
    unsigned int x[4][3] = {(1,2,3),(4,5,6),(7,8,9),(17,11,12)};
    printf("%d, %u, %u, %u \n",**x, **(x+1), **(x+2), **(x+3));
    return 0;
}

The output of the above code is 3, 12, 0, 0. Shouldn't it be 1,4,7,17 as x stores the address of first element of a array?

When I tried to print

printf("%u, %u \n", x, &x[0][0] );

it shows the same address 2108666688, 2108666688

But when I try to print the array using

for(int i = 0; i<4; ++i)
{
    for(int j = 0; j<3 ; ++j)
    {
        printf("%d ",x[i][j]);
    }
    printf("\n");
}

I see the output as

3 6 9 
12 0 0 
0 0 0 
0 0 0 

So, what exactly is happening here? Why are the numbers not getting assigned correctly to the array?

Upvotes: 1

Views: 66

Answers (3)

Vlad from Moscow
Vlad from Moscow

Reputation: 310970

Due to as I think a typo (there are used parentheses instead of braces) this declaration

unsigned int x[4][3] = {(1,2,3),(4,5,6),(7,8,9),(17,11,12)};

is equivalent to

unsigned int x[4][3] = { 3, 6, 9, 12 };

All other elements of the array are zero-initialized.

As result the array looks like it was explicitly initialized the following way

unsigned int x[4][3] = { { 3, 6, 9 }, { 12, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } };

That is for example this expression

(1,2,3)

is an expression with the comma operator that yields the value of the last operand.

From the C Standard (6.5.17 Comma operator)

2 The left operand of a comma operator is evaluated as a void expression; there is a sequence point between its evaluation and that of the right operand. Then the right operand is evaluated; the result has its type and value.

Consider for example

unsigned int x = ( 1, 2, 3 );
printf( "x = %u\n", x );

To get the expected result you have to substitute the parentheses with braces. For example

unsigned int x[4][3] = { {1,2,3}, {4,5,6}, {7,8,9}, {17,11,12} };

Upvotes: 1

Some programmer dude
Some programmer dude

Reputation: 409176

Remember that arrays naturally decays to pointers to their first element. That means in your case that x by itself is the same as &x[0].

Because x is an array of arrays, the type of &x[0] is a pointer to an array, in this case unsigned int (*)[3]. Dereferencing this pointer is an array (of type int [3]), which in turn can decay to a pointer to its first element.

What the double dereferencing does is simply dereferencing the two pointers, resulting in the first element of the first array, i.e. x[0][0].

That this happens to be 3 instead of 1 is because you initialize the elements using (1, 2, 3) which is using the comma expression which results in 3.

What you probably want to do is using curly-braces for the "inner" arrays as well:

unsigned int x[4][3] = {{1,2,3},{4,5,6},{7,8,9},{17,11,12}};

Now **x will result in 1 instead.

Another thing to remember is that for any array or pointer x and index i, the expression x[i] is equal to *(x + i).

Upvotes: 1

P.P
P.P

Reputation: 121387

unsigned int x[4][3] = {(1,2,3),(4,5,6),(7,8,9),(17,11,12)};

is functionally equivalent to:

unsigned int x[4][3] = {3, 6, 9, 12};

because of comma operator is at work here! comma operator evaluates all its operands and yields the result of of its last operand.

So the output you see is expected. You probably meant:

unsigned int x[4][3] = {{1,2,3},{4,5,6},{7,8,9},{17,11,12}};

Upvotes: 6

Related Questions