Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

which definition is better?

Tags:

c

#include<stdio.h>
int main(int argc , char *argv[])
{
    int array[2][2] = {{1,100},{1000,10000}};

    int *pointer    = array;
    int *ppointer   = &array;
    int *pppointer  = array[0];
    int *ppppointer = &array[0];

    printf("%d\n",*pointer);
    printf("%d\n",*ppointer);
    printf("%d\n",*pppointer);
    printf("%d\n",*ppppointer);

    return 0;
}

Four pointers are point to the first element of array. which definition shown above is better? And I don't known why the same value to array and &array?

like image 250
std Avatar asked Jul 21 '12 19:07

std


3 Answers

The only reason all for of your definitions compile is that your C compiler is too permitting when it comes to pointer type conversions. If you use some switches that make it more pedantic in this regard, it should immediately tell you that only the third initialization is valid, while the rest are erroneous.

In most contexts (with a few exceptions) when array of type T[N] is used in an expression, it "decays" (gets implicitly converted) to pointer type T * - a pointer that points to its first element. In other words, in such contexts for any array A, the A expression is equivalent to &A[0]. The only contexts where array type decay does not occur are unary & operator, sizeof operator and string literal used as an initializer for a char array.

In your example array is a value of int [2][2] type. When used on the right-hand side of initialization it decays to pointer type int (*)[2]. For this reason this is invalid

int *pointer    = array;

The right-hand side is int (*)[2], while the left-hand side is int *. These are different pointer types. You can't initialize one with the other.

The

int *ppppointer = &array[0];

is exactly equivalent to the previous one: the right-hand side produces a value of int (*)[2] type. It is invalid for the very same reason.

The &array expression produces a pointer of int (*)[2][2] type. Again, for this reason

int *ppointer   = &array;

is invalid.

The only valid initialization yo have in your example is

int *pppointer  = array[0];

array[0] is an expression of int [2] type, which decays to int * type - the same type that you have on the left-hand side.

In other words there's no question of which one "better" here. Only one of your initialization is valid, others are illegal. The valid initialization can also be written as

int *pppointer  = &array[0][0];

for the reasons I described above. Now, which right-hand side is "better" (array[0] or &array[0][0]) is a matter of your personal preference.


In order to make your other initializations valid, the pointers should be declared as follows

int (*pointer)[2]     = array;
int (*ppointer)[2][2] = &array;
int (*ppppointer)[2]  = &array[0];

but such pointers will have different semantics from an int * pointer. And you apparently need int * specifically.

like image 191
AnT Avatar answered Oct 06 '22 00:10

AnT


Only the third actually does the right thing. All other three are invalid C++ and cause warnings in my C compiler. It is often preferable to write C that is also valid C++, because on some platforms the C++ compiler is the also recommended compiler for C also (MSVC). This also makes it easier to include C code in a C++ project without significant build-system fiddling.

Why does your compiler complain about about 1, 2 and 4? Neither of the expressions on the right hand side have the right type to be converted to int*.

  1. array has type int[2][2] it can be converted to int(*)[2], not int*
  2. &array is a pointer to an int[2][2]
  3. array[x] has actually type int*
  4. &array[x] has type int**
like image 44
pmr Avatar answered Oct 06 '22 00:10

pmr


int *pointer    = array;     //Incorrect
int *ppointer   = &array;    //Incorrect
int *pppointer  = array[0];  //Correct
int *ppppointer = &array[0]; //Incorrect

That's the short version. Now for the reasons.

The first pointer is incorrect, because you're assigning 'array' (which is a pointer without any further specification)...but not one of int, but one of int *[]

The second pointer is incorrect, since you'd be assigning the address of the pointer...essentially the address of the variable, which holds the pointer to the data.

The third one is correct, because you get a pointer to an int array, regardless of size.

The fourth one is incorrect, since you're copying the address of the first array. That makes it an int **, and not a int *.

Sorry for the many edits...I must be tired.

like image 24
ATaylor Avatar answered Oct 06 '22 00:10

ATaylor