Why isn't a pointer value equal to address of struct it points to?
Here is the code I used to learning the way pointing to struct works. as you can see below, value of variable s
isn't equal to address of struct it points to (&amity
), strangely *s
equals to it.
Here are some more questions I have too:
Why address of all struct instances (and even &instance.name
) are the same?
While s
and i
and j
are the same, why does value of *j
differ from *s
and *i
?
And lastly why do value of a struct, equal to value of it first field only?
The code is a modified one from book Head First C.
#include <stdio.h>
typedef struct island {
char *name;
char *open;
char *close;
struct island *next;
} island;
void text(island *s);
int main(void) {
island amity = { "Amity", "09:00", "17:00", NULL };
island craggy = { "Craggy", "09:00", "17:00", NULL };
island isla_nublar = { "Isla Nublar", "09:00", "17:00", NULL };
island shutter = { "Shutter", "09:00", "17:00", NULL };
amity.next = &craggy;
craggy.next = &isla_nublar;
isla_nublar.next = &shutter;
printf("amity: %s\t &amity: %p\t &amity.name:%p \n", amity, &amity, &amity.name);
printf("craggy: %s\t &craggy: %p\t &craggy.name:%p \n", craggy, &craggy, &craggy.name);
printf("shutter: %s &shutter: %p\t &shutter.name:%p \n\n", shutter, &shutter, &shutter.name);
text(&amity);
}
void text(island *s) {
island *i = s;
island *j = i;
printf("s: %p\t i: %p\t j:%p\n", s, i, j);
printf("&s: %p\t &i: %p\t &j:%p\n", &s, &i, &j);
printf("*s: %p\t *i: %p\t *j:%p\n\n", *s, *i, *j);
for (; i != NULL; i = i->next) {
printf("Name: %s open: %s-%s\n", i->name, i->open, i->close);
}
}
and here is the result :
amity: Amity &amity: 0040302A &amity.name:00403030
craggy: Craggy &craggy: 0040302A &craggy.name:00403030
shutter: Shutter &shutter: 0040302A &shutter.name:00403030
s: 0060FEF0 i: 0060FEF0 j:0060FEF0
&s: 0060FEA0 &i: 0060FE8C &j:0060FE88
*s: 00403024 *i: 0040302A *j:00403030
Name: Amity open: 09:00-17:00
Name: Craggy open: 09:00-17:00
Name: Isla Nublar open: 09:00-17:00
Name: Shutter open: 09:00-17:00
Turn on warnings in your compiler, pay attention to them, and fix them. With GCC, start with -Wall
. With Clang, start with -Wmost
. With Microsoft Visual C++ (MSVC), start with /W4
. Also elevate warnings to errors. With GCC or Clang, use -Werror
. With MSVC, using /Wx
.
Why address of all struct instances (and even &instance.name) are the same?
They are not. In your printf
calls, you passed arguments of types that mismatch the conversion specifiers. This effectively corrupted the data that printf
operated on, so its output does not show you the actual values of the arguments. For example, in:
printf("amity: %s\t &amity: %p\t &amity.name:%p \n", amity, &amity, &amity.name);
the %s
requires a char *
argument, but the corresponding argument is a structure. In your C implementation, the structure may have been passed by copying its bytes to the stack. This results in the pointer, amity.name
, being in the position where %s
expects to find a pointer, so printf
“worked” by using that pointer to print a string. However, then %p
expects a pointer but what is on the stack after the first pointer for %s
is more bytes of the structure, not the &amity
argument. Because the structure was passed on the stack, it is taking up space, and the &amity
argument comes later. So printf
, when looking for the pointer for %p
, does not find the &amity
argument; it finds some bytes from later in the structure and converts those as if they were a pointer.
Thus, your output is corrupt and does not show you the values of &amity
or &amity.name
.
While s and i and j are the same, why does value of *j differ from *s and *i ?
In printf("*s: %p\t *i: %p\t *j:%p\n\n", *s, *i, *j);
, you again pass structures (*s
, *i
, and *j
are each structures) where printf
expects pointers. The output is corrupted.
Once you fix your printf
calls so that argument types match the conversion specifiers, you will see correct addresses.
And lastly why do value of a struct, equal to value of it first field only?
The value of a structure does not equal the value of its first field. Any impression you got of that from the test program shown in the question is incorrect due to the corrupted output.
However, the address of a structure does equal the address of the first field, because the first field starts at the beginning of the structure, which is of course where the structure starts.
Pointers can be hard to think about at first. But one way that does not really help to understand them is to write down all combinations of &
and *
and look for patterns in the results. The code you have posted contains so many meaningless combinations that it's basically impossible to say what it does.
Whenever you use &
or *
, you should be able to explain what it does. &
takes the address of something — makes a pointer to something — and if you wanted to print this address, you would always use %p
. *
takes the "contents" of a pointer — the value that it points to — and if you wanted to print this thing, you would use a printf
format corresponding to the type of the pointed-to thing.
Here is a modified version of your program that prints only meaningful combinations and that explains, I think, the kinds of questions you were trying to answer.
int main (void) {
island amity = {"Amity", "09:00", "17:00", NULL};
island craggy = {"Craggy", "10:00", "17:00", NULL};
island isla_nublar = {"Isla Nublar", "09:00", "18:00", NULL};
island shutter = {"Shutter", "10:00", "18:00", NULL};
amity.next = &craggy;
craggy.next = &isla_nublar;
isla_nublar.next = &shutter;
printf("&amity: %p\t &amity.name:%p \t &amity.open:%p \n",
&amity, &amity.name, &amity.open);
printf("&craggy: %p\t &craggy.name:%p \t &craggy.open:%p \n",
&craggy, &craggy.name, &craggy.open);
printf("&shutter: %p\t &shutter.name:%p \t &shutter.open:%p \n",
&shutter, &shutter.name, &shutter.open);
text(&amity);
}
void text (island *s) {
island *i;
printf("s: %p\n", s);
for(i = s ; i !=NULL ; i = i->next){
printf("Name: %s open: %s-%s\n", i->name, i->open , i->close);
}
}
In main
, this program prints the address of the structure, the address of its first member, and the address of its second member. On my computer, it prints
&amity: 0x7ffee17349b0 &amity.name:0x7ffee17349b0 &amity.open:0x7ffee17349b8
&craggy: 0x7ffee1734990 &craggy.name:0x7ffee1734990 &craggy.open:0x7ffee1734998
&shutter: 0x7ffee1734950 &shutter.name:0x7ffee1734950 &shutter.open:0x7ffee1734958
s: 0x7ffee17349b0
Name: Amity open: 09:00-17:00
Name: Craggy open: 10:00-17:00
Name: Isla Nublar open: 09:00-18:00
Name: Shutter open: 10:00-18:00
In each case, the address of the first member of the structure is the same as the address of the structure, as expected. The address of the second member is slightly greater, by sizeof(char *)
, which is 8 on my machine.
In text()
, I'm printing just the value of the pointer that's passed in, which is the same as the address of amity
, as expected. (I also made the opening and closing times of the four islands different, so we can confirm that were printing them correctly.)
It makes no sense at all to try to print an entire structure using printf
, as you requested when you wrote
printf("amity: %s\t &amity: %p\t &amity.name:%p \n", amity, &amity, &amity.name);
I'm surprised your compiler let you get away with that.
See Eric Postpischil's answer for many more explanations.