4

I am learning passing 2D arrays to functions in C and learned that I can receive 2D array in the function as following:

  1. void test(char a[5][10])
  2. void test(char (*a)[10])

Above declarations work for me but looking on **argv parameter of function main I thought of changing my function to void test(char **a). But this does not work correctly. I do not understand why. Please explain.

Here is my code

#include<stdio.h>

int main(int argc, char **argv){
    char multi[5][10] = {
                         {'0','0','2','3','4','5','6','7','1','9'},
                         {'a','b','c','d','e','f','g','h','i','j'},
                         {'A','B','C','D','E','F','G','H','I','J'},
                         {'9','8','7','6','5','4','3','2','1','0'}, 
                         {'J','I','H','G','F','E','D','C','B','A'}
                        };
    test(multi);
    return 0;
}

void test(char (*a)[10]) // void test(char **a) does not work
{
    printf("\n a[2][1] is: %d",*(*(a + 2)+1));
}
Grijesh Chauhan
  • 57,103
  • 20
  • 141
  • 208
Sensiblewings47
  • 558
  • 1
  • 5
  • 16
  • Please have a read about arrays and pointers in C. `char*` and `char[N]` are often interchangeable, but not always, this is one such case. – filmor Jul 10 '13 at 06:38
  • @chris Exactly. But then how **argv works? It is also a pointer right? – Sensiblewings47 Jul 10 '13 at 06:38
  • 1
    A pointer to an array and a pointer to a pointer are not the same thing, and you can't use one in place of another. `argv` already has a pointer at the first level of indirection, so it's only ever a pointer to a pointer. – chris Jul 10 '13 at 06:39
  • It is a pointer to an array of pointers. – filmor Jul 10 '13 at 06:39
  • Especially in C++ (which I can only assume is allowed, considering it's a tag), where you can pretty much forget about types and use `std::cout`. – chris Jul 10 '13 at 06:42
  • 2
    [This](http://stackoverflow.com/questions/13974001/two-dimensional-array-implementation-using-double-pointer) may help for better understanding. – Dayal rai Jul 10 '13 at 06:45

6 Answers6

4

An array name when passed to a function will decay to the value of the address of its first element, and its type will be a pointer to that element type. Since the type of multi[0] is a char[10], then multi will decay pointer to char[10].

main() receives an array of pointers to char in its second parameter, which is why argv can be char **argv or char *argv[].

jxh
  • 69,070
  • 8
  • 110
  • 193
4

For multidimensional arrays, rows are stored in continuous memory locations. That's why we need to pass the number of columns, i.e., to calculate the number of items to jump over to get to a specific row.

In case of pointer to pointers, rows are stored in arbitrary memory locations. You cannot find the location of a row given the pointer to the first row and an index. In this case, you need as much pointers as you have rows.

In short, the two versions of your function arguments assume different memory layouts and as such, they are incompatible.

perreal
  • 94,503
  • 21
  • 155
  • 181
2

Array in C is in essence one dimensional. When passing multi-dimensional array you should pass every dimension size except for the first one as constant integer. And the array is in passed as a pointer, not an array. Here is an alternative: Passing one dimensional or multi-dimensional pointer, along with demension sizes. For example: void test(char *a, int row, int column); and the index is: column * i + j; or: void test(char **a, int row, int column);

lulyon
  • 6,707
  • 7
  • 32
  • 49
1

char (*a)[10] is a pointer to an array of characters. The operation (a+1) will increment the value of a by 10 bytes.

char **a is a double pointer. In this case, the operation (a+1) will increment the value of a by 4 bytes. Hence the below statement would result in erroneous behaviour.

printf("\n a[2][1] is: %d",*(*(a + 2)+1));

Nithin Bhaskar
  • 686
  • 1
  • 5
  • 9
0

This is not a formal explanation but that's how I understand it: Arrays are actually stored linear in memory. For example, you define a 10x10 array and do b=a[4][5], system will go to find the 4*10+5=45th element in memory. That's why you cannot pass **a and access it as a 2D-array. It's a pointer without dimension information. With a[4][5], the program will go to find the 4*(number of columns)+5th element. Since it doesn't know how many elements there is in a row, it cannot do that.

Manas
  • 598
  • 3
  • 14
0

You can always do something like this

#include<stdio.h>
#include<stdlib.h>
void test(char **a);
int main(int argc, char **argv){
    char **multi = (char**) malloc (5*sizeof(char*));
    char a[5][10] = {{'0','0','2','3','4','5','6','7','1','9'}, {'a','b','c','d','e','f','g','h','i','j'}, {'A','B','C','D','E','F','G','H','I','J'}, {'9','8','7','6','5','4','3','2','1','0'}, {'J','I','H','G','F','E','D','C','B','A'}};
    int i,j;
    for(i=0;i<5;i++)
    {
        multi[i] = (char*) malloc (10*sizeof(char));
    }
    for(i = 0;i<5;i++) 
    {
        for(j = 0; j < 10 ;j++)
        {
            multi[i][j] = a[i][j];

        }
    }
    test(multi);
    return 0;
}

void test(char **a) // void test(char **a) does not work
{
    printf("\n a[2][1] is: %c\n",*(*(a + 2)+1));
}
learner
  • 1,952
  • 7
  • 33
  • 62