Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the difference between a and a + 0 as C pointers?

Look at the C code.

#include <stdio.h>
int main(void)
{
    int v[3] = {1, 2, 3};
    printf("%d\n", v);
    printf("%d\n", v + 0);
    printf("%zu\n", sizeof(v));
    printf("%zu\n", sizeof(v + 0));
    printf("%zu\n", sizeof(v + 1));
    printf("%zu\n", sizeof(v + 2));
    return 0;
}

Here's one of the outputs:

-587904464
-587904464
12
8
8
8

I think v is the same as v + 0.

Both are pointers pointing to the first element in array v[3].

Therefore, v and v+0 have the same value.

But why do they fail to hold the same bytes? (sizeof(v) and sizeof(v + 0) are different )

like image 391
Sleeping On a Giant's Shoulder Avatar asked Jan 01 '23 20:01

Sleeping On a Giant's Shoulder


1 Answers

An array identifier decays to a pointer to the first element of the array, in most cases. But, when an array is the operand of the sizeof operator, this conversion does not take place, and the operator yields the size of the array in bytes. From §6.3.2.1 ¶3 of the C11 Draft Standard:

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.

Note that in the C18 Standard the _Alignof operator has been removed from this passage (discussion here).

So, sizeof(v) yields the size of the array v[] in bytes, which is 12 bytes. That is, the type of the operand is int [3] since the array has not been converted to a pointer to int (as it would be in most expressions), and the sizeof operator yields the size of this type (an array of 3 ints) in bytes.

But with sizeof (v + 0) the type of the expression v + 0 determines the result yielded by the sizeof operator. In the expression v + 0, the array v[] decays to a pointer to the first element of v[], and then 0 is added according to the rules of pointer arithmetic. The result is a pointer to int (since &v[0] is itself a pointer to int), so the type of the expression v + 0 is int *. The sizeof operator thus yields the size of a pointer to int in this case. The same holds for the similar expressions sizeof (v + 1), etc.

As an aside, note that you must print addresses with the %p conversion specifier after first casting to void * to avoid undefined behavior:

printf("%p\n", (void *)v);
printf("%p\n", (void *)(v + 0));
like image 109
ad absurdum Avatar answered Jan 12 '23 20:01

ad absurdum