zchenkui
zchenkui

Reputation: 139

C language pointers: int ** Vs. int (*g)[]

everyone.

I use Visual Studio 2013 (C++) and defined a 2d array in main function:

int _tmain(int argc, char **argv) 
{
    int g[3][3] = { { 1, 2, 3, }, { 4, 5, 6, }, { 7, 8, 9, }, };
    ...

    return 0;
}

then, I defined a function in Define 1:

Define 1:

void print_array(int **arr, int kx, int ky)
{
    for (int i = 0; i < kx; i++) {
        for (int j = 0; j < ky; j++) {
            printf("%d ", arr[i][j]);
        }
        printf("\n");
    }
}

I want to call this function from main function:

int _tmain(int argc, char **argv) 
{
    int g[3][3] = { { 1, 2, 3, }, { 4, 5, 6, }, { 7, 8, 9, }, };

    print_array(g, 3, 3);

    return 0;
}

The visual studio tells me that:

Error   1   error C2664: 'void print_array(int **,int,int)' : cannot convert argument 1 from 'int [3][3]' to 'int **'

I also know another definition method:

Define 2

void print_array(int (*arr)[3], int kx, int ky)
{
    for (int i = 0; i < kx; i++) {
        for (int j = 0; j < ky; j++) {
            printf("%d ", arr[i][j]);
        }
        printf("\n");
    }
}

Now it works.

My question is: I remenbered before that they (Define 1 and Define 2) worked both in old compiler, named you can pass array name as int ** or int (*p) [] correctly to another function. However in Visual Studio C++ it is not. Is Visual Studio C++ much stricter than other compiler ? Or I did something wrong?

Thank you very much!

Upvotes: 0

Views: 775

Answers (3)

John Bode
John Bode

Reputation: 123458

Except when it is the operand of the sizeof or unary & operators, or is a string literal used to initialize a character 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 of the array.

When you call print_array( g, 3, 3 );, the expression g has type “3-element array of T”, where T is “3-element of int”. So g will “decay” to type “pointer to T”, or “pointer to 3-element of int”, or int (*)[3]. That’s why your second definition works.

Here’s a handy table to help remember some of these rules:

Type            Decays to
————            —————————
T [N]           T *
T [M][N]        T (*)[N]
T [L][M][N]     T (*)[M][N]

Upvotes: 1

Dietrich Epp
Dietrich Epp

Reputation: 213338

I remenbered before that they (Define 1 and Define 2) worked both in old compiler,

If the memory is correct, the old compiler was broken. The code was never valid C.

You can convert an array, int x[3], to a pointer, int *p, freely. This has always worked, and there are many cases where it happens implicitly.

However, int (*x)[3] is a pointer and int **y is a pointer, but they point to completely different types of objects! You can't convert a int * to a double * either.

You can see that x and y have different structure if you draw them out:

+-------------+       +-----+
| int (*x)[3] | ----> | int |
+-------------+       | --- |
                      | int |
                      | --- |
                      | int |
                      +-----+
                      | ... |

+---------+       +-------+       +-----+
| int **y | ----> | int * | ----> | int |
+---------+       +-------+       +-----+
                  |  ...  |       | ... |

They don't look the same at all, do they?

Upvotes: 6

iBug
iBug

Reputation: 37227

Array and pointer conversion can only be done on the 1st level, so int* and int[] fit well into each other, but not int** and int[][].

Actually, int** (can be converted to int(*)[]) points to an array of pointers, each of which can point to different locations, but obviously the sub-arrays of a 2D array can't. That's the problem you're facing.

Upvotes: 1

Related Questions