3
int main()
{

    struct a
    {
        struct a *next;
        struct a *prev;
    };

    struct a *A[2];

    printf("Address of (&(A[0])->next) = %p",(&(A[0])->next));
    getch();
    return 0;
}

In the above printf statement I'm accessing "next" pointer of "struct a" structure & when I run the program in dev compiler it's giving me the valid memory address (though I've not yet allocated any memory for it). An explanation of how come this happens will be very helpful.

Is any memory allocated for the "next" & "prev" fields?

Bart
  • 19,692
  • 7
  • 68
  • 77
CoolToshi45
  • 155
  • 2
  • 10
  • 4
    But is it a correct memory address? No, AFAICS you're dereferencing an uninitialised pointer so if it works it's a fluke. Note that you're not actually allocating any memory for As at all - you're telling it you have an array of pointers to As. The only thing you're allocating is memory to store those pointers. – Rup Jun 05 '13 at 11:35
  • It may happen consistently yes, e.g. it's reusing some part of the stack frame that previously pointed to some init structure or somewhere else on the stack. But there's no guarantee what's there will be a valid pointer, and if you e.g. compile this in debug mode with most compilers it'll initialise the stack to an invalid pointer, e.g. something that's an odd number like 0xCCCCCCCC, and it'll definitely fail. – Rup Jun 05 '13 at 11:39
  • The `printf`-statement itself is pretty valid, the data you try to print however, is not. Dereferencing unitialized pointers will result in [undefined behaviour](http://en.wikipedia.org/wiki/Undefined_behavior), which can result in programs which _might_ do what you want, but they could also set your cat on fire. – Zeta Jun 05 '13 at 11:39
  • @ Rup i think this fluke is happening everytime. + if i modify my printf to printf("Address of (&(A[0])->next) = %p", (((struct a *)(&(A[0])))->next)); fluke will never happen – CoolToshi45 Jun 05 '13 at 11:41

2 Answers2

9

Let's think about what this means:

&(A[0])->next

It is the address of the next pointer (not where it points, but the address of the pointer itself). And the next pointer is the first element of struct a, so the address of next is the same as the address of its enclosing a.

Therefore, the expression is the address of the struct a referred to by A[0]. In your original code, you never assign anything there, so it's simply a garbage value being printed. As @alk points out in another answer, you could initialize the two pointers in your variable A and then you would see the first of those values being printed (say, 0x0).

By the way, if you want to quickly initialize A, do it this way, not with the more verbose memset():

struct a *A[2] = {0};

It does the same thing (sets the two pointers to 0).

While the value being printed is garbage, the code may not be illegal. This may seem surprising, but see here: Dereferencing an invalid pointer, then taking the address of the result - you've got something similar, though admittedly you've taken it a step further by dereferencing a member of a struct as opposed to simply using *. So the open question in my mind is: given that &*foo is always legal when foo is a pointer (as shown in the above link), does the same hold true for &foo->bar?

Community
  • 1
  • 1
John Zwinck
  • 239,568
  • 38
  • 324
  • 436
  • Note that the question you linked to is on C++, so the answer may actually be different for C. – Shahbaz Jun 05 '13 at 11:55
  • @Shahbaz: no, the question is tagged C++, but much of the discussion is about C specifically, and it says that `&*foo` is always legal in C, even if it's unclear in C++. – John Zwinck Jun 05 '13 at 11:58
  • `struct a *A[2] = {};` is a C++ construct. In C, you need an initialiser in the braces, `struct a *A[2] = {{0}};` for example. – Daniel Fischer Jun 05 '13 at 12:00
  • @DanielFischer: thanks, updated `{}` (which GCC accepts if you don't use -pedantic) to `{0}`. – John Zwinck Jun 05 '13 at 13:35
4
&(A[0])->next

is the address of the next member of the first structure in the A array.

This can be thought of as &A[0] + offsetof(struct a, next). I. e., this just results in whatever the value of the uninitialized pointer A[0] was plus the offset of the next member from the base address of the structure (which happens to be zero, since next is the first element of the structure).

According to the C standard, your program invokes undefined behavior because it performs pointer arithmetic on an invalid pointer. However, in practice, this will most likely not crash and print a bogus address (only an addition is performed, nothing accesses the memory behind the pointer). Expect a crash though if you actually dereference the pointer.