Reputation: 1513
Using a simple sample that involves an array point generates the following warnings. The code codes compile and execute which also leads to questions.
This is the int Array. int numbers[3] = { 101, 202, 303};
These 2 calls generate the warnings.
int *p2 = &numbers;
int **p3 = &numbers;
The following are the Warning generated.
> cc -o myApp test.c
test.c: In function 'main':
test.c:9:12: warning: initialization from incompatible pointer type [enabled by default]
int *p2 = &numbers;
^
test.c:10:13: warning: initialization from incompatible pointer type [enabled by default]
int **p3 = &numbers;
^
The code used is the following :
#include <stdio.h>
int main ()
{
int numbers[3] = { 101, 202, 303};
int size = sizeof(numbers) / sizeof (numbers[0]);
int *p = numbers;
int *p2 = &numbers;
int **p3 = &numbers;
int *p4 = &numbers[0];
int *end = p + size;
printf("p = 0x%d\n", p);
printf("p2 = 0x%d\n", p2);
printf("p3 = 0x%d\n", p3);
printf("numbers = 0x%d\n", numbers);
printf("&numbers = 0x%d\n", &numbers);
printf("numbers[0] = 0x%d\n", numbers[0]);
printf("&numbers[0] = 0x%d\n", &numbers[0]);
for (; p != end; p++)
{
printf ("0x%d\n", p);
}
}
When executed, here is the output.
> ./runTest
p = 0x-207214704
p2 = 0x-207214704
p3 = 0x-207214704
numbers = 0x-207214704
&numbers = 0x-207214704
numbers[0] = 0x101
&numbers[0] = 0x-207214704
0x-207214704
0x-207214700
0x-207214696
Both p2 and p3 as well as p all point to the same address. I really thought using p3 as a double pointer would have resolved the Warning, but it appears not. Why does p2 and p3 generate the Warnings and what is it trying to say?
Upvotes: 1
Views: 194
Reputation: 123448
First, always use %p
to print pointer values:
printf( "%p\n", (void *) p );
printf( "%p\n", (void *) p1 );
Given the declaration
int numbers[3];
then the following are true:
Expression Type "Decays" to Value
---------- ---- ----------- -----
numbers int [3] int * Address of first element of array
&numbers int (*)[3] n/a Address of array (which is the same as above)
*numbers int n/a Value of numbers[0]
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 "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. Thus, under most circumstances (such as when it's the RHS of an assignment, or a parameter to a function), the expression numbers
will have type int *
.
So how do you properly initialize p2
and p3
? That depends on what you want to happen when you write p2 + 1
or p2[1]
and p3 + 1
or p3[1]
. If you want p2 + 1
to point to the second element in numbers
, or if you want p2[1]
to be equal to numbers[1]
, then you'd write
int *p2 = numbers;
If you want p2 + 1
to point to the next 3-element array of int
following the end of the numbers
array, then you'd write
int (*p2)[3] = &numbers;
Then you'd initialize p3
as
int **p3 = &p2;
or
int (**p3)[3] = &p2;
based on how p2
was declared.
A picture might help. Assume the following declarations:
int numbers[3] = { 0, 1, 2 };
int *p0 = numbers;
int (*p1)[3] = &numbers;
then things look something like this:
+---+
numbers: | 0 | numbers[0] <------ p0, p1
+---+
| 1 | numbers[1] <------ p0 + 1
+---+
| 2 | numbers[2]
+---+
... <------ p1 + 1
Remember that with pointer arithmetic, p + 1
points to the next object of the pointed-to type; if p
points to an object that's 4 bytes wide, then p + 1
points to the object starting 4 bytes after p
. If p
points to an object that's 32 bytes wide (such as a small array), then p + 1
points to the object starting 32 bytes after p
.
Upvotes: 2
Reputation: 30926
I get the point which causes you this confusion. You first saw
int *p = numbers;
Well don't think that numbers
is of type pointer. It is simply an array object (int[3]
) which is converted into pointer to first element of it - that is int*
. This is known as array decaying.
Now you think in int **p3 = &numbers;
- &numbers
will be of type int**
.
Well this is where the trick is - array decaying doesn't occure in some cases - when array is used as an operand to &
operator - then it is one case like this - so it won't decay. It will be an array object whose pointer is considered which is int(*)[3]
in this case.
With this logic int *p2=&numbers
will also be something of which compiler will complain. The correct would be what is said here int (*pp)[3] = &numbers
. Note that print the pointers(not a function pointer) use %p
format specifier with the argument cast to void*
.
The compiler tried to warn you about the pointer type mismatch. (For pointers the type to which it points to is of importance because of the pointer arithmetic is dictated by that).
From §6.3.2.1p3
Except when it is the operand of the
sizeof
operator, the_Alignof
operator, or the unary&
operator, or is a string literal used to initialize an array, an expression that has type "array of type" is converted to an expression with type "pointer to type" that points to the initial element of the array object and is not an lvalue.
Upvotes: 3
Reputation: 21955
It should have been
int numbers[3] = { 101, 202, 303};
and
int (*p2)[3] = &numbers; // Here p2 is a pointer to an array of 3 members
The members should be accessed like
(*p2)[0],(*p2)[1] and (*p2)[2]
which is eqivalent to
*(*(p2)+0),*(*(p2)+1) and *(*(p2)+2)
and also to
p2[0][0],p2[0][1] and p2[0][2] // Since array notation can be used to dereference pointers.
Upvotes: 1