为什么structure和next的地址不一样?

Why the address of structure and next is not same?

#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>

struct node
{
    int id;
    struct node *next;
};
typedef struct node NODE;
int main()
{
    NODE *hi;   
    printf("\nbefore malloc\n");
    printf("\naddress of node is: %p",hi);
    printf("\naddress of next is: %p",hi->next);
return 0;
}

输出为:

在 malloc 之前

节点地址为:0x7ffd37e99e90 下一个地址是:0x7ffd37e9a470

为什么两者不一样?

你这里没有malloc。 hi 指针指向未定义的内容。 嗨->下一个一样。

关于问题。为什么他们应该是?

我觉得你不懂指针。

TL;DR

您的代码引发了 未定义的行为,正如 中已经提到的那样。除此之外,您似乎在理解指针的工作方式方面遇到了问题。请参阅教程参考资料。


首先,来自您的评论

在这种情况下,当您说为 ip 分配了内存时:

int i = 10;
int *ip;
ip = &i;

发生的情况是:

  1. 您声明了一个名为 iint 变量,并将值 10 赋给它。这里,计算机在栈上为这个变量分配了内存。比如说,地址 0x1000。所以现在,地址 0x1000 有内容 10.
  2. 然后声明一个名为 ip 的指针,类型为 int。计算机为指针分配内存。 (这很重要,请参阅下面的解释)。您的指针位于地址 0x2000.
  3. 当您分配 ip = &i 时,您将变量 i 地址分配给变量 ip。现在变量ip(你的指针)的i的地址。 ip 不包含值 10 - i 包含。将此赋值视为 ip = 0x1000实际上不要编写此代码)。
  4. 要使用您的指针获取值 10,您必须执行 *ip - 这称为取消引用指针。当你这样做时,计算机将访问指针所在地址的内容,在这种情况下,计算机将访问i地址上的内容,这是 10。将其视为:get the contents of address 0x1000.

在那段代码之后,内存看起来像这样:

VALUE    :   10    | 0x1000 |
VARIABLE :    i    |   ip   |
ADDRESS  :  0x1000 | 0x2000 |

指针

指针是 C 中的一种特殊类型的变量。您可以将指针视为保存地址 的类型化变量。 space 您的计算机在堆栈上分配的指针取决于您的 体系结构 - 在 32bit 机器上,指针将占用 4 个字节;在 64bit 机器上,指针将占用 8 个字节。那是您的计算机为您的指针分配的唯一内存(足够的空间来存储地址)。

但是,指针保存内存地址,因此您可以使它指向某个内存块...就像从 malloc 返回的内存块一样。


所以,考虑到这一点,让我们看看您的代码:

NODE *hi;   
printf("\nbefore malloc\n");
printf("\naddress of node is: %p",hi);
printf("\naddress of next is: %p",hi->next);
  1. 声明一个指向 NODE 的指针,名为 hi。让我们想象这个变量 hi 有地址 0x1000,并且那个地址 内容是任意的——你没有初始化它,所以它可以是从零开始的任何东西ThunderCat.
  2. 然后,当您在 printf 中打印 hi 时,您正在打印该地址 0x1000 的内容...但是您不知道那里有什么.. . 可以是任何东西。
  3. 然后取消引用 hi 变量。你告诉计算机:访问 ThunderCat 的内容并打印变量 next 的值。现在,我不知道 ThunderCats 内部是否有变量,也不知道它们是否愿意被访问...所以这是 未定义的行为。而且不好!

要解决这个问题:

NODE *hi = malloc(sizeof NODE);
printf("&hi: %p\n", &hi);
printf(" hi: %p\n", hi);

现在你有一个结构大小的内存块来保存一些数据。但是,您仍然没有初始化它,所以访问它的内容是仍然是未定义的行为

要初始化它,您可以这样做:

hi->id = 10;
hi->next = hi;

现在您可以打印任何您想要的东西。看到这个:

#include <stdio.h>
#include <stdlib.h>

struct node {
    int id;
    struct node *next;
};

typedef struct node NODE;

int main(void)
{
    NODE *hi = malloc(sizeof(NODE));

    if (!hi) return 0;

    hi->id = 10;
    hi->next = hi;

    printf("Address of hi (&hi)   : %p\n", &hi);
    printf("Contents of hi        : %p\n", hi);
    printf("Address of next(&next): %p\n", &(hi->next));
    printf("Contents of next      : %p\n", hi->next);
    printf("Address of id         : %p\n", &(hi->id));
    printf("Contents of id        : %d\n", hi->id);

    free(hi);

    return 0;
}

并且输出:

$ ./draft
Address of hi (&hi)   : 0x7fffc463cb78
Contents of hi        : 0x125b010
Address of next(&next): 0x125b018
Contents of next      : 0x125b010
Address of id         : 0x125b010
Contents of id        : 10

变量hi的地址是一个,它指向的地址是另一个。此输出有几点需要注意:

  1. hi 在堆栈上。它指向的块在堆上。
  2. id的地址与内存块相同(那是因为它是结构的第一个元素)。
  3. next的地址距离id有8个字节,而它应该只有4个(毕竟int只有4个字节长)——这是内存的原因结盟。
  4. next的内容与hi所指向的块相同。
  5. hi 指针本身的内存量 "alloced" 是 8 个字节,因为我正在处理 64bit。这就是它拥有和需要的所有房间
  6. malloc 之后总是 free。避免 memory leaks
  7. 除了学习之外,不要为了其他目的而编写这样的代码。

注意:当我说 "memory alloced for the pointer" 时,我的意思是 space 当声明发生在 Stack Frame 设置之后时,计算机在堆栈上为它分离。


参考资料

因为next是指针类型,指向0x7ffd37e9a470。 如果打印 if next &(hi->next) 的地址,可以看到 hi 和 hi->next 都相差 2(因为 int id 是第一个元素)。