为什么指针值不等于它指向的结构地址?
Why isn't a pointer value equal to address of struct it points to?
这是我用来学习指向结构的工作方式的代码。正如您在下面看到的,变量 s
的值不等于它指向的结构地址 (&amity
),奇怪的是 *s
等于它。
这里还有一些我也有的问题:
为什么所有结构实例(甚至 &instance.name
)的地址都相同?
虽然 s
和 i
和 j
相同,但为什么 *j
的值与 *s
和 *i
不同?
最后为什么结构的值只等于它第一个字段的值?
该代码是对《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);
}
}
结果如下:
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
打开编译器中的警告,注意它们并修复它们。对于 GCC,从 -Wall
开始。对于 Clang,从 -Wmost
开始。对于 Microsoft Visual C++ (MSVC),以 /W4
开头。还将警告提升为错误。对于 GCC 或 Clang,使用 -Werror
。使用 MSVC,使用 /WX
.
Why address of all struct instances (and even &instance.name) are the same?
他们不是。在您的 printf
调用中,您传递的参数类型与转换说明符不匹配。这有效地破坏了 printf
操作的数据,因此它的输出不会向您显示参数的实际值。例如,在:
printf("amity: %s\t &amity: %p\t &amity.name:%p \n", amity, &amity, &amity.name);
%s
需要一个char *
参数,但是对应的参数是一个结构体。在您的 C 实现中,结构可能已通过将其字节复制到堆栈来传递。这导致指针 amity.name
位于 %s
期望找到指针的位置,因此 printf
通过使用该指针打印字符串“有效”。但是,%p
需要一个指针,但在 %s
的第一个指针之后堆栈中的内容是结构的更多字节,而不是 &amity
参数。因为结构是在堆栈上传递的,所以它占用了 space,&amity
参数在后面。所以printf
,在寻找%p
的指针时,没有找到&amity
参数;它从结构的后面找到一些字节并将它们转换为指针。
因此,您的输出已损坏,不会向您显示 &amity
或 &amity.name
的值。
While s and i and j are the same, why does value of *j differ from *s and *i ?
在 printf("*s: %p\t *i: %p\t *j:%p\n\n", *s, *i, *j);
中,您再次传递结构(*s
、*i
和 *j
都是结构),其中 printf
需要指针。输出已损坏。
修复 printf
调用使参数类型与转换说明符匹配后,您将看到正确的地址。
And lastly why do value of a struct, equal to value of it first field only?
结构的值不等于其第一个字段的值。由于输出损坏,您从问题中显示的测试程序中得到的任何印象都是不正确的。
但是,结构的地址确实等于第一个字段的地址,因为第一个字段从结构的开头开始,这当然是结构的开始。
一开始可能很难想到指针。但是 而不是 真正有助于理解它们的一种方法是写下 &
和 *
的所有组合并在结果中寻找模式。您发布的代码包含太多无意义的组合,基本上不可能说出它的作用。
无论何时使用 &
或 *
,您都应该能够解释它的作用。 &
获取某物的地址——指向某物——如果你想打印这个地址,你总是会使用 %p
。 *
获取指针的“内容”——它指向的值——如果你想打印这个东西,你会使用与指向的东西的类型相对应的 printf
格式.
这是你的程序的修改版本,它只打印有意义的组合,我认为它解释了你试图回答的问题类型。
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);
}
}
在main
中,此程序打印结构的地址、第一个成员的地址和第二个成员的地址。在我的电脑上,它打印
&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
在每种情况下,结构的第一个成员的地址与预期的结构地址相同。第二个成员的地址稍微大一点,sizeof(char *)
,在我的机器上是8。
在 text()
中,我只打印传入的指针的值,正如预期的那样,它与 amity
的地址相同。 (我还把四个岛的开放和关闭时间弄得不一样,所以我们可以确认打印是正确的。)
尝试使用 printf
打印整个结构完全没有意义,正如您在编写
时所要求的那样
printf("amity: %s\t &amity: %p\t &amity.name:%p \n", amity, &amity, &amity.name);
我很惊讶你的编译器让你侥幸逃脱。
有关更多解释,请参阅 Eric Postpischil 的回答。
这是我用来学习指向结构的工作方式的代码。正如您在下面看到的,变量 s
的值不等于它指向的结构地址 (&amity
),奇怪的是 *s
等于它。
这里还有一些我也有的问题:
为什么所有结构实例(甚至 &instance.name
)的地址都相同?
虽然 s
和 i
和 j
相同,但为什么 *j
的值与 *s
和 *i
不同?
最后为什么结构的值只等于它第一个字段的值?
该代码是对《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);
}
}
结果如下:
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
打开编译器中的警告,注意它们并修复它们。对于 GCC,从 -Wall
开始。对于 Clang,从 -Wmost
开始。对于 Microsoft Visual C++ (MSVC),以 /W4
开头。还将警告提升为错误。对于 GCC 或 Clang,使用 -Werror
。使用 MSVC,使用 /WX
.
Why address of all struct instances (and even &instance.name) are the same?
他们不是。在您的 printf
调用中,您传递的参数类型与转换说明符不匹配。这有效地破坏了 printf
操作的数据,因此它的输出不会向您显示参数的实际值。例如,在:
printf("amity: %s\t &amity: %p\t &amity.name:%p \n", amity, &amity, &amity.name);
%s
需要一个char *
参数,但是对应的参数是一个结构体。在您的 C 实现中,结构可能已通过将其字节复制到堆栈来传递。这导致指针 amity.name
位于 %s
期望找到指针的位置,因此 printf
通过使用该指针打印字符串“有效”。但是,%p
需要一个指针,但在 %s
的第一个指针之后堆栈中的内容是结构的更多字节,而不是 &amity
参数。因为结构是在堆栈上传递的,所以它占用了 space,&amity
参数在后面。所以printf
,在寻找%p
的指针时,没有找到&amity
参数;它从结构的后面找到一些字节并将它们转换为指针。
因此,您的输出已损坏,不会向您显示 &amity
或 &amity.name
的值。
While s and i and j are the same, why does value of *j differ from *s and *i ?
在 printf("*s: %p\t *i: %p\t *j:%p\n\n", *s, *i, *j);
中,您再次传递结构(*s
、*i
和 *j
都是结构),其中 printf
需要指针。输出已损坏。
修复 printf
调用使参数类型与转换说明符匹配后,您将看到正确的地址。
And lastly why do value of a struct, equal to value of it first field only?
结构的值不等于其第一个字段的值。由于输出损坏,您从问题中显示的测试程序中得到的任何印象都是不正确的。
但是,结构的地址确实等于第一个字段的地址,因为第一个字段从结构的开头开始,这当然是结构的开始。
一开始可能很难想到指针。但是 而不是 真正有助于理解它们的一种方法是写下 &
和 *
的所有组合并在结果中寻找模式。您发布的代码包含太多无意义的组合,基本上不可能说出它的作用。
无论何时使用 &
或 *
,您都应该能够解释它的作用。 &
获取某物的地址——指向某物——如果你想打印这个地址,你总是会使用 %p
。 *
获取指针的“内容”——它指向的值——如果你想打印这个东西,你会使用与指向的东西的类型相对应的 printf
格式.
这是你的程序的修改版本,它只打印有意义的组合,我认为它解释了你试图回答的问题类型。
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);
}
}
在main
中,此程序打印结构的地址、第一个成员的地址和第二个成员的地址。在我的电脑上,它打印
&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
在每种情况下,结构的第一个成员的地址与预期的结构地址相同。第二个成员的地址稍微大一点,sizeof(char *)
,在我的机器上是8。
在 text()
中,我只打印传入的指针的值,正如预期的那样,它与 amity
的地址相同。 (我还把四个岛的开放和关闭时间弄得不一样,所以我们可以确认打印是正确的。)
尝试使用 printf
打印整个结构完全没有意义,正如您在编写
printf("amity: %s\t &amity: %p\t &amity.name:%p \n", amity, &amity, &amity.name);
我很惊讶你的编译器让你侥幸逃脱。
有关更多解释,请参阅 Eric Postpischil 的回答。