Reputation: 8335
I am new to C and got stuck on "How to pass multidimensional array to a function". I do understand that you have to pass column size so that if you want to go from a[0][0]
to a[1][0]
it can calculate the size of 1-D array and can jump over it.
I have written a small program:
#include<stdio.h>
void foo(char[][2]);
int main()
{
char arr[2][2] = {'a','b','c','d'};
foo(arr);
return 0;
}
void foo(char temp[][2])
{
temp++;
printf("%c",*temp);
}
I expected that this code will print the letter c
, since temp
initially points to 'a'
and once we increment it, it will skip over first 1-d array and go to first element of second 1-d array which is 'c'
. But it does not work that way I guess.
Please explain the how compiler computes these addresses.
Upvotes: 2
Views: 175
Reputation: 123488
Except when it is the operand of the sizeof
or unary &
operator, or is a string literal being used to initialize another 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 in the array.
In main
, the type of the expression arr
in the function call foo(arr)
is "2-element array of 2-element array of char
"; since it isn't the operand of the sizeof
or unary &
operators, it "decays" to an expression of type "pointer to 2-element array of char
", or char (*)[2]
.
Thus, the parameter temp
is type char (*)[2]
, and it points to the first element of arr
. The parameter declaration char temp[][2]
is equivalent to char (*temp)[2]
. The expression *temp
is equivalent to temp[0]
, and both have type "2-element array of char
" (char [2]
). The expression temp + 1
gives you the address of the next 2-element array of char
, so *(temp + 1)
is equivalent to temp[1]
.
Here's a table to summarize all of that:
Expression Type Decays To Value
---------- ---- --------- -----
arr char [2][2] char (*)[2] &arr[0][0]
*arr char [2] char * arr[0]
&arr char (*)[2][2] n/a &arr[0][0]
arr[i] char [2] char * &arr[i][0]
*arr[i] char n/a arr[i][0]
&arr[i] char (*)[2] n/a &arr[i][0]
arr[i][j] char n/a arr[i][j]
temp char (*)[2] n/a &arr[0][0]
*temp char [2] char * arr[0]
&temp char (**)[2] n/a addr of temp variable
temp[i] char [2] char * &arr[i][0]
*temp[i] char n/a arr[i][0]
&temp[i] char (*)[2] n/a &arr[i][0]
temp[i][j] char n/a arr[i][j]
arr + 1 char [2][2] char (*)[2] &arr[1][0]
*(arr + 1) char [2] char * arr[1]
temp + 1 char (*)[2] n/a &arr[1][0]
*(temp + 1) char [2] char * arr[1]
arr[0][0] char n/a 'a'
arr[0][1] char n/a 'b'
arr[1][0] char n/a 'c'
arr[1][1] char n/a 'd'
**temp char n/a 'a'
*temp[0] char n/a 'a'
temp[0][0] char n/a 'a'
**(temp + 1) char n/a 'c'
*temp[1] char n/a 'c'
temp[1][0] char n/a 'c'
So, in your print statement, you would write either
printf("%c", **temp); // temp == &arr[1][0] after temp++
or
printf("%c", *temp[0]); // temp[0] == arr[1] after temp++
or
printf("%c", temp[0][0]); // temp[0][0] == arr[1][0] after temp++
The expressions arr
, &arr
, *arr
, arr[0]
, &arr[0]
, *arr[0]
, and &arr[0][0]
all yield the same value - the address of the first element of arr
(remember that the address of the array and the address of the first element of the array are the same). They just differ in type.
Note that &temp
gives us a different value than &arr
. Since temp was declared as a pointer, not an array, &temp
gives us the address of the pointer variable.
A picture may help:
+---+
arr: |'a'| arr[0][0] <------------------+ before temp++
+---+ |
|'b'| arr[0][1] |
+---+ |
|'c'| arr[1][0] <--+ after temp++ |
+---+ | |
|'d'| arr[1][1] | |
+---+ | |
... | |
+---+ | |
temp: | |---------------+---------------+
+---+
Upvotes: 3
Reputation: 12263
For function argument char temp[][2]
, temp
decays to a pointer. But only for the first (outer) dimension. So it is effectively a pointer to array [2]
of char
.
Incrementing the pointer will advance it to the next outer index, as you already assumed.
So, you either have to use (*temp)[0]
or **temp
to get the first element. **temp
works, because *temp
is an array itself, so it decays to a pointer to the first element of the inner array. The second (left) *
then dereferences this pointer: c
.
Note that, allthough it uses the same syntax like char **temp
, they are fundamentally different. A pointer is not an array and here, incrementing temp
will only advance by the size of a pointer, which is not what you want.
Note that the initializer would better be according to the 2-simensional nature:
{ { 'a', 'b' } , { 'c', 'd' } }
This ensures you get the correct values for the inner arrays and is good practice. Omitting a value in the non-nested form will result in wrong sequence for the inner array. When having enabled the recommended warnings (-Wall
) at least, gcc warns about missing braces.
Upvotes: 3
Reputation: 75062
The pointer arithmetic is good. You just forgot to dereference *temp
, which has type char[2]
.
Change it to **temp
, and you'll get an output c
.
Upvotes: 6