views:

189

answers:

7

If the following is possible:

MyFunction(int *array, int size)
{
    for(int i=0 ; i<size ; i++)
    {
        printf(“%d”, array[i]);
    }
}

main()
{
    int array[6] = {0, 1, 2, 3, 4, 5};
    MyFunction(array, 6);
}

Why the following is not?

MyFunction(int **array, int row, int col)
{
    for(int i=0 ; i<row ; i++)
    {
        for(int j=0 ; j<col ; j++)
        {
            printf(“%d”, array[i][j]);
        }
    }
}

main()
{
    int array[3][3] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
    MyFunction(array, 3, 3);
}
A: 

Because a pointer pointer isn't the same type as a pointer to an array. See http://stackoverflow.com/questions/3457578/pointers-to-pointers-and-pointer-arrays for details.

Also, this has some good info: http://c-faq.com/aryptr/index.html

JoshD
+5  A: 

Edit: Here's my attempt at a more to-the-point answer as requested and based on your new example code:

Regardless of the array dimensions, what you pass is a "pointer to an array" - it's only a single pointer, though the type of the pointer can vary.

In your first example, int array[6] is an array of 6 int elements. Passing array passes a pointer to the first element, which is an int, hence the parameter type is int *, which can be equivalently written as int [].

In your second example, int array[3][3] is an array of 3 rows (elements), each containing 3 ints. Passing array passes a pointer to the first element, which is an array of 3 ints. Hence the type is int (*)[3] - a pointer to an array of 3 elements, which can be equivalently written as int [][3].

I hope you see the difference now. When you pass an int **, it is actually a pointer to an array of int *s and NOT a pointer to a 2D array.

An example for an actual int ** would be something like this:

int a[3] = { 1, 2, 3 };
int b[3] = { 4, 5, 6 };
int c[3] = { 7, 8, 9 };
int *array[3] = { a, b, c };

Here array is an array of 3 int *s, and passing this as an argument would result in an int **.


Original answer:

Your first example isn't really a 2D array, although it is used in a similar way. There, you're creating ROWS number of char * pointers, each of which points to a different array of COLS characters. There are two levels of indirection here.

The second and third examples are actually 2D arrays, where the memory for the entire ROWS * COLS characters is contiguous. There is only one level of indirection here. A pointer to a 2D array is not char **, but char (*)[COLS], so you can do:

char (*p)[SIZE] = arr;
// use p like arr, eg. p[1][2]
casablanca
A: 

The first example is possible because arrays degenerate to pointers when passed as function parameters.

The second example does not work because int[3][3] degenerates to int (*)[3], not a double pointer int **. This is the case because 2D arrays are contiguous in memory, and without this information the compiler would not know how to access elements past the first row. Consider a simple grid of numbers:

1  2  6 
0  7  9

If we were storing these numbers in an array int nums[6], how would we index into the array to access the element 7? By 1 * 3 + 1, of course, or more generally, row * num-columns + column. In order to access any element past the first row, you need to know how many columns the grid has.

When you store the numbers as nums[2][3], the compiler uses the exact same row * num-columns + column arithmetic as you do manually with a 1D array, it's just hidden from the programmer. Therefore, you must pass the number of columns when passing a 2D array in order for the compiler to be able to carry out this arithmetic.

In many other languages, arrays carry information about their size, eliminating the need to manually specify dimensions when passing multi-dimensional arrays to functions.

Justin Ardini
A: 

Perhaps we can expect a more "to the point" question, if you want to have a more to the point answer. Your idea has two problems:

  1. a 2D array int A[3][3] when used in an expression decays to the address of its first element thus to a pointer of type int (*)[3]. To be able to pass the array through you'd have to use &A[0][0] to get a pointer to the first "inner" member.
  2. inside your function the operation A[i][j] can't be performed since your compiler has no information of the row length, there.
Jens Gustedt
+1  A: 

The others have pretty much summed it up. int **A means that A is a pointer to an array and not a reference to a 2-D array. However, that does not mean it is not usable. Since the data in C is stored in row-major order, once you know the row length, retrieving the data should be easy

Anurag
A: 
nategoose
+2  A: 
John Bode