Unexpected result when assigning and printing pointer value of two-dimensional array with its name

42 views Asked by At

From my understanding of two-dimensional arrays, let's say if I declare int a[3][3] = {1, 2, 3, 4, 5, 6, 7, 8, 9};, it will be stored in a memory in exact order.

And the address of each row can be written like this:
a[0] is equal to &a[0][0], a[1] is equal to &a[1][0], and a[2] is equal to &a[2][0]. So each a[n] is a int* type variable.

And since array name a is originally &a[0], it will be a int** type variable.

From this knowledge, I assumed that writing code like this will occur error when assigning a to p, since the type is different.

#include <stdio.h>

int main() {
    int a[3][3] = { 72, 4, 5,
                   6, 7, 8,
                   9, 10, 11 };

    int* p;
    p = a;    //possible error, from int** to int*

    printf("*p : %d\n", *p);
    return 0;
}

But somehow the result shows the value of a[0][0], which is 72. What happened here? Am I understanding something wrong about two-dimensional matrix?

2

There are 2 answers

0
Vlad from Moscow On

And since array name a is originally &a[0], it will be a int** type variable.

You are wrong. Arrays used in expressions with rare exceptions are indeed converted to pointers to their first elements. But in this case the type of elements of the array is int[3]. So the array a used in expressions is converted to a pointer of the type int ( * )[3].

As for this code snippet

int* p;
p = a;    //possible error, from int** to int*

printf("*p : %d\n", *p);

then values of addresses of the expressions a, a[0] and &a[0][0] (it is the value of the address of the extent of memory occupied by the array) are equal each other. So using the value and interpreting it as a value of the type &a[0][0] you will get the value of the first element a[0][0].

0
Eric Postpischil On

So each a[n] is a int* type variable.

No. The type of a[n] is int [3], which is an array of 3 int.

int * is a pointer to an int.

These are different things. In memory, an array of 3 int has bytes for 3 int objects, and those bytes contain the values of the int. In memory, an int * has bytes for an address, and those bytes contain the values of the address.

In an expression, a[n] will be automatically converted to the address of its first element except when it is the operand of sizeof or of unary &. This conversion is performed by taking the address of a[n][0], and then the result will be an int *. But, to work with C properly, you must remember that a[n] is actually an array, even though this conversion is automatically performed.

And since array name a is originally &a[0], it will be a int** type variable.

No. The type of a is int [3][3]. As with a[n], in an expression, it will be automatically converted to a pointer to its first element except when it is the operand of sizeof or unary &. The result will be &a[0], and the type of that will be int (*)[3], which is a pointer to an array of 3 int.

This will not be further converted to int **. The result of the automatic conversion will be a pointer to a place in memory where there are bytes representing 3 int. An int ** would point to a place in memory where there are bytes representing an address.

p = a; //possible error, from int** to int*

Since the result of the automatic conversion of a has type int (*)[3] and p has type int *, this attempts to assign an int (*)[3] to int *. This violates the constraints for simple assignment in C 2018 6.5.16.1 1, so the C implementation is required to issue a diagnostic message for it.

Then the behavior is not defined by the C standard. However, most C implementations will convert the int (*)[3] to int * and produce a pointer to the first int in a.