Robin
Robin

Reputation: 81

Creating a pointer to a 2D array

I am new to C and spend some hours with arrays and pointers. Now, I got a specific question I can't really answer by myself. What are the two variables mat_ptr and ptr which I create in this example and why are they different? To me it looks like each is an array of pointers storing the pointers to the beginning of the 3 rows of the matrix.

int matrix[3][3] = {{0,1,2}, 
                    {0,1,2},
                    {0,1,2}};

int (*mtr_ptr)[3] = matrix;

int *ptr[3];
for (int i=0; i< 3; i++)
{
   ptr[i]=matrix[i];
}

I the end, I think ptr ist of type int ** but what exactly is ptr_ptr?

A pointer to an array of size 3 which is an array of arrays?

Upvotes: 1

Views: 101

Answers (4)

John Bode
John Bode

Reputation: 123598

Unless it is the operand of the sizeof or unary & operators, or is a string literal used to initialize a character array in a declaration, an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T" and the value of the expression will be the address of the first element of the array.

In the line

int (*mtr_ptr)[3] = matrix;

the expression matrix has type "5-element array of 5-element array of int". Since matrix is not the operand of the sizeof or unary & operators, it "decays" to type "pointer to 5-element array of int", or int (*)[5], and its value is the address of the first element of matrix (same as &matrix[0]).

int (*)[5] and int (*)[3] are different, incompatible types, so the compiler should yak at you on that initializer. You should declare mtr_ptr as

int (*mtr_ptr)[5] = matrix;

Remember that mtr_ptr is a pointer, not an array - it stores a single value. That single value has type int (*)[5].

By contrast, the expression matrix[i] has type "5-element array of int"; by the same rule above, that expression "decays" to type "pointer to int", or int *. Since each element of your ptr array is storing an int *, you declare it as

int *ptr[3];

In this case ptr is an array, and each element simply stores an int *. That pointer may be the address of the first element matrix[i], or it may be a pointer to a single int object that isn't part of a larger array, or it may be something else:

ptr[0] = matrix[0];
ptr[1] = &i;
...

The size of ptr does not depend on the size of matrix beyond whether or not you want to store the address of all rows or matrix or just a subset.

Upvotes: 0

Vlad from Moscow
Vlad from Moscow

Reputation: 311146

These declarations

int matrix[5][5] = {{0,1,2,3}, 
                    {0,1,2,3},
                    {0,1,2,3}}

int (*mtr_ptr)[3] = matrix;

do not make a sense. It seems you mean at least the following declarations

int matrix[3][4] = {{0,1,2,3}, 
                    {0,1,2,3},
                    {0,1,2,3}};

int (*mtr_ptr)[4] = matrix;

According to the C Standard (6.3.2.1 Lvalues, arrays, and function designators)

3 Except when it is the operand of the sizeof operator or the unary & operator, or is a string literal used to initialize an array, an expression that has type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points to the initial element of the array object and is not an lvalue. If the array object has register storage class, the behavior is undefined.

So the array matrix used in expressions with rare exceptions is converted to pointer to its initial element of the type int ( * )[4].

Thus in this declaration

int (*mtr_ptr)[4] = matrix;

the pointer mtr_ptr is initialized by the address of the first "row" of the array matrix.

On the other hand, the expression matrix[i] is the i-th element of the array matrix that has the type int[4]. Such an array used in expression is in turn converted to pointer to its first element of the type int *.

In this line

int *ptr[3];

there is declared an array of three elements of the type int *.

And in this loop

for (int i=0; i< 3; i++)
{
   ptr[i]=;
}

each element of the array of pointers is assigned by the address of the first element of the corresponding "row" of the array matrix that ("row") used in the expression matrix[i] is implicitly converted to pointer.

Upvotes: 0

Ian Abbott
Ian Abbott

Reputation: 17513

First things first. There is a semi-colon missing from the definition of matrix, corrected below:

int matrix[5][5] = {{0,1,2,3}, 
                    {0,1,2,3},
                    {0,1,2,3}};

Regarding the definition of mtr_ptr below:

int (*mtr_ptr)[3] = matrix;

mtr_ptr is declared as a pointer to an array length 3 of ints. However, it is being initialized with an incompatible pointer. matrix is an array length 5 of array length 5 of int. In the assignment expression above, matrix is converted to a pointer to the first element. The elements of matrix have type array length 5 of int, so matrix is converted to a pointer to array length 5 of int with value equivalent to &matrix[0]. Therefore, mtr_ptr should be defined as:

int (*mtr_ptr)[5] = matrix;

or equivalently:

int (*mtr_ptr)[5] = &matrix[0];

Regarding the code below:

int *ptr[3];
for (int i=0; i< 3; i++)
{
   ptr[i]=matrix[i];
}

ptr is defined as an array length 3 of pointers to int. matrix[i] is an array length 5 of int. In the assignment expression, it is converted to a pointer to its first element. The element type is int, so matrix[i] is converted to a pointer to int equivalent to &matrix[i][0]. Therefore, the assignement ptr[i]=matrix[i]; is equivalent to ptr[i]=&matrix[i][0];.

Upvotes: 0

Eric Postpischil
Eric Postpischil

Reputation: 224546

This code:

int matrix[5][5] = {{0,1,2,3}, 
                    {0,1,2,3},
                    {0,1,2,3}}

is missing a semicolon at the end. When that is fixed, it defines matrix to be a 5×5 array (formally an array of 5 arrays of 5 int) in which rows 0 to 2 are initialized with four values (0, 1, 2, and 3), leaving element 4 implicitly initialized to zero. Rows 3 to 4 are implicitly initialized to zero.

This code:

int (*mtr_ptr)[3] = matrix;

defines mtr_ptr to be a pointer to an array of 3 int and attempts to initialize it with matrix. Since matrix is an array, it will be automatically converted to a pointer to its first element, matrix[0]. Thus, we have a pointer to an array of 5 int. This is not a proper type to initialize a pointer to an array of 3 int, so the compiler will complain.

If matrix were defined as int matrix[5][3] or int matrix[3][3], and the then-excess initializers were removed, then the types in int (*mtr_ptr)[3] = matrix; would match, and the compiler would not complain.

This code:

int *ptr[3];
for (int i=0; i< 3; i++)
{
   ptr[i]=matrix[i];
}

defines an array of 3 pointers to int and assigns them values from matrix[i]. Since each matrix[i] is an array, it will be converted to a pointer to its first element, matrix[i][0]. So each ptr[i] will be assigned to point to matrix[i][0].

Upvotes: 2

Related Questions