Search code examples
cgccpointersaddressof

"Address of" (&) an array / address of being ignored be gcc?


I am a teaching assistant of a introductory programming course, and some students made this type of error:

char name[20];
scanf("%s",&name);

which is not surprising as they are learning... What is surprising is that, besides gcc warning, the code works (at least this part). I have been trying to understand and I wrote the following code:

void foo(int *v1, int *v2) {
  if (v1 == v2)
    printf("Both pointers are the same\n");
  else
    printf("They are not the same\n");
}

int main() {
  int test[50];
  foo(&test, test);
  if (&test == test)
    printf("Both pointers are the same\n");
  else
    printf("They are not the same\n");
}

Compiling and executing:

$ gcc test.c -g
test.c: In function ‘main’:
test.c:12: warning: passing argument 1 of ‘foo’ from incompatible pointer type
test.c:13: warning: comparison of distinct pointer types lacks a cast
$ ./a.out 
Both pointers are the same
Both pointers are the same

Can anyone explain why they are not different?

I suspect it is because I cannot get the address of an array (as I cannot have & &x), but in this case the code should not compile.

Edit: I know that an array by itself is the same as the address of the first element, but this is not related to this problem, I think. For example:

int main() {
  int a[50];
  int * p = a;
  printf("%d %d %d\n", p == a, p == &a[0], &p[0] == a);
  printf("%d %d %d\n", p == &a, &p == a, &p == &a);
}

prints:

$ ./a.out 
1 1 1
1 0 0

I don't understand why the second line begins with 1.


Solution

  • In your example, the array test is a block of 50 ints. So it looks like this:

    | int | int | ... | int |
    

    When you apply the unary & operator to an array, you get the address of the array. Just like when you apply it to anything else, really. So &test is a pointer that points to that block of 50 ints:

    (&test) -----------> | int | int | ... | int |
    

    A pointer that points to an array of 50 ints has type int (*)[50] - that's the type of &test.

    When you just use the name test in any place where it's not the operand of either the sizeof or unary-& operators, it is evaluated to a pointer to its first element. So the test that you pass to foo() evaluates to a pointer to the test[0] element:

    (test) -----------------\
                            v
    (&test) -----------> | int | int | ... | int |
    

    You can see that these both are pointing to the same address - although &test is pointing to the whole array, and test is pointing to the first element of the array (which only shows up in the different types that those values have).