为什么指针值不等于它指向的结构地址?

Why isn't a pointer value equal to address of struct it points to?

这是我用来学习指向结构的工作方式的代码。正如您在下面看到的,变量 s 的值不等于它指向的结构地址 (&amity),奇怪的是 *s 等于它。

这里还有一些我也有的问题:

为什么所有结构实例(甚至 &instance.name)的地址都相同?

虽然 sij 相同,但为什么 *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 的回答。