Toby
Toby

Reputation: 3905

Reference of an Array without Index in C

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

Answers (4)

John Bode
John Bode

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

Lundin
Lundin

Reputation: 213842

  • Never declare several variables on the same line. Or you will write bugs like 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

Attie
Attie

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

unalignedmemoryaccess
unalignedmemoryaccess

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_cand 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

Related Questions