eric.mcgregor
eric.mcgregor

Reputation: 3653

Cannot dereference multidimensional array as expected

int arr5[][3] = {{1,2,3}, {4,5,6}, {7,8,9}};

The variable declaring a 2D array holds a pointer to the first element in the first array. arr5 was defined as having 3 columns in each row. By adding 1 to arr5 we get the address of the first element in the second row, by adding 2 to arr5 we get the address of the first element in the third row.

int *row1 = arr5;
int *row2 = arr5 + 1;
int *row3 = arr5 + 2;

Dereferencing a pointer to an array gets the first element in the array.

printf("%d\n", *row1);  // prints 1
printf("%d\n", *row2);  // prints 4
printf("%d\n", *row3);  // prints 7

We can dereference the elements in those rows using [].

for (j = 0; j < 3; j++) {
  printf("%d%c", row1[j], (j==2)?'\n':' ');
} // prints 1 2 3

We can print the second row without using brackets. Row2 now holds the address of the first element in the second row.

for (j = 0; j < 3; j++) {
  printf("%d%c", *(row2+j), (j==2)?'\n':' ');
}  // prints 4 5 6

Why can't we substitute arr5+1 for row2 in the above example? row2 holds the address arr5+1.

for (j = 0; j < 3; j++) {
  printf("%d%c", *((arr5+1)+j), (j==2)?'\n':' ');
}  // prints what looks to be addresses

Upvotes: 2

Views: 110

Answers (2)

David C. Rankin
David C. Rankin

Reputation: 84521

Except when it is the operand of the sizeof operator, the _Alignof 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. C11 Standard - 6.3.2.1 Other Operands - Lvalues, arrays, and function designators(p3)

So when you access arr5, you are effectively using a pointer to array of int [3]. When you attempt to assign:

int *row1 = arr5;

You are attempting to assign arr5 which has type int(*)[3] to row1 which is int* resulting in the warning:

"initialization from incompatible pointer type"

To eliminate the warning you need to derefernce arr5 resulting in type int[3] (which on access is converted to a pointer to the first element in the row) which is compatible with int*. For example, rearranging your example a bit, you could do:

#include <stdio.h>

int main (void) {

    int arr5[][3] = {{1,2,3}, {4,5,6}, {7,8,9}},
        *row1 = *arr5,
        *row2 = *(arr5 + 1),
        *row3 = *(arr5 + 2);
    size_t  nrow = sizeof arr5 / sizeof *arr5,
            ncol = sizeof *arr5 / sizeof **arr5;

    puts ("By row:");
    for (size_t j = 0; j < ncol; j++)       /* output row1 */
        printf ("%3d", *(row1 + j));
    putchar ('\n');

    for (size_t j = 0; j < ncol; j++)       /* output row2 */
        printf ("%3d", *(row2 + j));
    putchar ('\n');

    for (size_t j = 0; j < ncol; j++)       /* output row3 */
        printf ("%3d", *(row3 + j));
    putchar ('\n');

    puts ("\nBy array:");
    for (size_t i = 0; i < nrow; i++) {     /* output arr5 */
        for (size_t j = 0; j < ncol; j++)
            printf ("%3d", *(*(arr5 + i) + j));
        putchar ('\n');
    }
}

(note: row1[j] and arr5[i][j] are generally more readable than their pointer notation equivalents)

Example Use/Output

$ ./bin/ptr2arrayauto
By row:
  1  2  3
  4  5  6
  7  8  9

By array:
  1  2  3
  4  5  6
  7  8  9

Look things over and let me know if you have further questions.

Upvotes: 4

chux
chux

Reputation: 153338

Heed compiler warnings. *((arr5+1)+j) is not an int, but an int *.

warning: format '%d' expects argument of type 'int', but argument 2 has type 'int *' [-Wformat=]

Note: (arr5+1)+j is the same as (arr5+1+j). I suspect OP wanted *(arr5+1)+j here.

int main() {
    int arr5[][3] = {{1,2,3}, {4,5,6}, {7,8,9}};
    for (int j = 0; j < 3; j++) {
      printf("%d%c", *((arr5+1)+j), (j==2)?'\n':' '); // Warning here!!
    } 

    for (int j = 0; j < 3; j++) {
      printf("%d%c", *(*(arr5+1)+j), (j==2)?'\n':' ');
      //               ^ 
    }
return 0;
}

Output

-13412 -13400 -13388  UB UB UB
4 5 6                 OK OK OK

Upvotes: 3

Related Questions