I am new to programming in C and I am trying to understand the concept of pointers. However, the result of some print statements are quite confusing and I was not able to find suitable answers online.
So, I was running the following main
function in C:
int main() {
int a[] = { 1, 2, 3, 4, 5 }; // a points to the address of a[0]
int *p = a; // p points to the same address as a
int **pp = &p; // points to p
int *p2[] = { a, a+1, a+2, a+3, a+4 }; // points a
int **pp2 = p2; // points to the same address as p2
printf(" a: %p, *a: %p\n", a, *a);
printf(" p: %p, *p: %p\n", p, *p);
printf(" pp: %p, *pp: %p, **pp: %p\n", pp, *pp, **pp);
printf(" p2: %p, *p2: %p, **p2: %p\n", p2, *p2, **p2);
printf("pp2: %p, *pp2: %p, **pp2: %p\n", pp2, *pp2, **pp2);
return 0;
}
With gcc main.c -o main
and ./main
I got the following output:
a: 0061FF04, *a: 00000001
p: 0061FF04, *p: 00000001
pp: 0061FEEC, *pp: 0061FF04, **pp: 00000001
p2: 0061FEF0, *p2: 0061FF04, **p2: 00000001
pp2: 0061FEF0, *pp2: 0061FF04, **pp2: 00000001
which indicates that both a
and p
point to a[0]
and pp
to p
, which is expected behavior. It also makes sense that p2
and pp2
point to the same address as a
, but I cannot think of a reason, why printing out a
and p
as well as p2
and pp2
results in the same address (0061FF04
and 0061FEF0
, respectively). Any help is appreciated
For starters all your calls to printf
have undefined behavior because you use an invalid conversion specifier p
with objects of the type int
. To output objects of the type int
you need to use conversion specifier d
or i
.
Arrays used in expressions with rare exceptions are implicitly converted to pointers to their first element.
From the C Standard (6.3.2.1 Lvalues, arrays, and function designators)
3 Except when it is the operand of the
sizeof
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. If the array object hasregister
storage class, the behavior is undefined.
For example in this declaration
int *p = a;
the array a
used as an initializing expression is implicitly converted to a pointer to its first element. You may equivalently rewrite the declaration the following way
int *p = &a[0];
Dereferencing the pointer p
as in *p
that is the same as *a
or p[0]
or a[0]
: you will get the first element of the array a
.
So you should write
printf(" a: %p, *a: %d\n", ( void * )a, *a);
printf(" p: %p, *p: %d\n", ( void * )p, *p);
In this declaration
int *p2[] = {a, a+1, a+2, a+3, a+4};
you define an array of pointers to elements of the array a
.
So for example the array designator p2
used in expressions is converted to a pointer to its first element.
So the pointer pp2
declared as
int **pp2 = p2;
also receives the address of the first element of the array p2
. That is the value of pp2
is equal to the value of p2
after implicit conversion of the array designator p2
to a pointer to its first element.
On the other hand, expressions *pp2
and *p2
, that are the same as pp2[0]
and p2[0]
, yield the first element of the array p2
. And expressions **pp2
and **p2
, that are the same as pp2[0][0]
and p2[0][0]
(or ( *pp2 )[0]
, (*p2 )[0]
or *pp2[0]
, *p2[0]
), yield the first element of the array a
because the first element of the array p2
contains the address of the first element of the array a
.
So you should write
printf(" p2: %p, *p2: %p, **p2: %d\n", ( void * )p2, ( void * )*p2, **p2);
printf("pp2: %p, *pp2: %p, **pp2: %d\n", ( void * )pp2, ( void * )*pp2, **pp2);
Though values of the expressions pp2
and p2
are equal (they both have the value of the address of the first element of the array p2
) the values of pp
and pp2
are different because the pointer pp
points to the pointer p
. However the values of expressions *pp2
and *pp
are equal because the both point to the first element of the array a
.