简体   繁体   中英

Pointer arithmetic and 2-D array in c?

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.

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 .

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.

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: |   |---------------+---------------+
      +---+

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM