Reputation: 3905
Assume the following example:
uint8 myArr[4] = {0, 1, 2, 3};
uint8* ptr_a, ptr_b, ptr_c, ptr_test;
uint8** ptrptr_c;
void main(void)
{
ptr_a = &myArr[4]; // Address of myArr
ptr_b = myArr; // Address of myArr
ptr_c = &myArr; // --> Address of myArr again?! <---
ptrptr_c = &myArr; // --> Address of myArr again?! <--
ptr_test = &ptr_a // Address of ptr_a (whose content points to myArr)
}
That ptr_a
and ptr_b
contain the address of myArr
is perfectly clear to me.
But I would've actually assumed, that ptr_c
would contain some kind of address where the address of myArr
is stored (analogue to ptr_test
).
So, why does ptr_c
(or ptrptr_c
) contain the address of myArr
?
Upvotes: 0
Views: 5290
Reputation: 123468
uint8* ptr_a, ptr_b, ptr_c, ptr_test;
Only ptr_a
has been declared as a pointer to uint8
; everything else has been declared as uint8t
.
Based on your assignments, the right types for each variable are
uint8 *ptr_a, *ptr_b, (*ptr_c)[4], (*ptrptr_c)[4], **ptr_test;
The expression &myArr[4]
has type uint8 *
, and evaluates to the address of the object one past the last element of the array (remember that arrays in C are indexed starting at 0).
The expression myArr
is implicitly converted ("decays") from type "4-element array of uint8
" to "pointer to uint8
" and the value of the expression is the address of the first element in the array - it's equivalent to writing &myArr[0]
.
Because of the presence of the &
operator, myArr
isn't implicitly converted to a pointer, so the type of &myArr
is "pointer to 4-element array of uint8
". The address of an array is the same as the address of the first element of the array, so &myArr[0]
, myArr
, and &myArr
will all yield the same value, but the won't all have the same type.
And finally, the type of &ptr_a
is "pointer to pointer to uint8
".
And, main
returns int
, not void
- use int main( void )
instead of void main()
.
Upvotes: 1
Reputation: 213842
uint8* ptr_a, ptr_b, ptr_c, ptr_test;
Only the first variable is declared as a pointer. ptr_c = &myArr is not a valid pointer conversion, since the type of &myArr
is uint8 (*)[4]
, an array pointer. An array pointer works just as any other pointer type, though it points at whole arrays. So my_array_pointer+1
gives you the next array, just like my_int_pointer+1
gives you the next int (the next pointed-at item).
An array pointer points to the whole array, so it will contain the address of the first item. Which is why myArr
and &myArr
gives the same address (but different types).
You cannot assign an array pointer to an ordinary pointer. This line should not compile without warnings/errors.
ptrptr_c = &myArr;
is the same invalid pointer conversion, except ptrptr_c
is a uint8**
. There is a common misunderstanding that pointer-to-pointers are somehow related to arrays. This is simply wrong, they are not related to arrays whatsoever. The origin of this misunderstanding is look-up tables like this:
int** pptr = malloc(n*sizeof(*pptr));
...
pptr[i] = malloc(n*sizeof(*pptr[i]));
Bad books/tutorials/teachers tend to say that the above is a 2D array, which it is not.
See Correctly allocating multi-dimensional arrays to unlearn this incorrect belief. It also explains array pointers a bit.
Upvotes: 4
Reputation: 6979
Arrays in C, can decay - see this answer.
This means that in the following, ptr_a
and ptr_b
are equivalent (the same).
Also, be aware that in the following, the assignment of ptr_d
is not valid (see the warning below).
#include <stdio.h>
#include <stdint.h>
int main(void) {
uint8_t myArr[4] = { 0, 1, 2, 3 };
uint8_t *ptr_a = myArr;
uint8_t *ptr_b = &(myArr[0]);
uint8_t *ptr_c = &(myArr[4]);
uint8_t *ptr_d = &myArr; /* <-- invalid (warning raised) */
printf("ptr_a: %p\n", ptr_a);
printf("ptr_b: %p\n", ptr_b);
printf("ptr_c: %p\n", ptr_c);
printf("ptr_d: %p\n", ptr_d);
return 0;
}
$ gcc aa.c -o aa && ./aa
aa.c: In function ‘main’:
aa.c:9:19: warning: initialization from incompatible pointer type [enabled by default]
uint8_t *ptr_c = &myArr;
^
$ ./aa
ptr_a: 0x7fffdda58cf0
ptr_b: 0x7fffdda58cf0
ptr_c: 0x7fffdda58cf4
ptr_d: 0x7fffdda58cf0
ptr_e: 0x7fffdda58cf0
Upvotes: 0
Reputation: 7441
Why again
? You apply 2 times the same code.
It does not care what type is variable and what you assign to it. You assign to ptr_c
and ptrptr_c
the same value. So they both contain the same value. This is in general veery wrong concept and compiler should warn you or give you error.
Correct value would be:
uint8 myArr[4] = {0, 1, 2, 3};
uint8 *ptr_a, *ptr_b, *ptr_c, *ptr_test;
uint8** ptrptr_c;
void main(void) {
//ptr_a = &myArr[4]; // Address of myArr //WRONG!!!!
ptr_a = &myArr[3]; //If you want last address, use 3, because 3 is last index.
ptr_b = myArr; // Address of myArr, OK!!
//ptr_c = &myArr; // WRONG: if ptr_c is pointer to uint8_t then assing uint8_t pointer to it.
ptr_c = myArr; //Correct!
//This should be compiler error something like:
//a value of type "uint8_t (*)[]" cannot be assigned to an entity of type "uint8_t **
ptrptr_c = &myArr; // Address of myArr again? No, error.
//This is WRONG
ptr_test = &ptr_a; // WRONG:
ptr_test = ptr_a; //THIS IS OK
}
Upvotes: 2