Reputation: 3653
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
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
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