【问题标题】:Why the address of structure and next is not same?为什么结构和下一个的地址不一样?
【发布时间】:2015-12-23 04:25:49
【问题描述】:
#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 next的地址是:0x7ffd37e9a470

为什么两者不一样?

【问题讨论】:

  • 你不会(m)分配任何东西,hi 指向任何地方。您的代码通过取消引用 hi(在 hi-&gt;next 中)表现出未定义的行为。
  • 比方说 int *a ,其中 a 指向一个整数类型,所以,就像这样,在上面的代码中我定义了 NODE *hi,它应该指向结构节点。内存已经为它创建好了,为什么还要重新分配?
  • 当您声明int * a 时,您会为指针保留内存,而不是它指向的内容。因此,就像您的NODE * hi; 一样,您获得了指针的内存,而不是目标,因此在分配它之前取消引用它是未定义的行为。声明一个指针不会为它所指向的内容分配内存。
  • 明白...谢谢,
  • 模式 struct node *next 所以它是结构的第一个成员。结构的地址和结构的第一个成员相同(可能即使地址未初始化)。在带有虚函数的 C++ 中可能有一个例外,(我读过一些内部数据可能在结构或类的第一个声明成员之前)。

标签: c malloc dynamic-memory-allocation


【解决方案1】:

TL;DR

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


首先,来自您的 cmets

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

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

会发生什么:

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

sn-p 代码后的内存是这样的:

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

指针

指针是 C 中一种特殊类型的变量。您可以将指针视为保存地址的类型化变量。您的计算机在堆栈上为指针分配的空间取决于您的架构 - 在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,并且该地址的内容 是任意的——你没有初始化它,所以它可以是从零到@987654323 的任何值@
  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 个(毕竟ints 只有 4 个字节长) - 这是由于内存对齐。
  4. next 的内容与hi 指向的块相同。
  5. hi 指针本身“分配”的内存量为 8 个字节,因为我正在处理 64bit。这就是它拥有和需要的所有房间
  6. 总是freemalloc 之后。避免memory leaks
  7. 切勿为学习以外的其他目的编写这样的代码。

注意:当我说“为指针分配的内存”时,我指的是在 Stack Frame 设置之后发生声明时计算机在堆栈上为其分隔的空间。


参考

【讨论】:

  • @Enzo Ferber 感谢您的解释,我有疑问,如果我们声明 'int a;'那么a是数据类型整数的变量,'int *p; p = &a;'意味着,p指向a,即它存储a的地址。但是,在结构的情况下,导致混淆的是,如果我们声明“结构节点”,那么那里的节点是什么?我认为它是可变的,所以如果我声明一个指向它的指针,那么它直接指向它。但总的来说,如果我们声明 'struct node var1;' ,那么var1是一个变量,能指出这种情况下var1和node的区别吗?
  • @lok​​esh1729 当您声明struct node *np; 时,您有一个指向类型 struct node 的变量的指针。这只会为地址分配空间。当您执行struct node myNode; 时,您声明了struct node 类型的变量——第二种方法使计算机为堆栈上的变量保留一些空间。如果你这样做 struct node myNode; struct node *np; np = &amp;myNode; 是正确的。但是,您仍然需要初始化myNode 上的变量才能使用它。
  • @lok​​esh1729 可能让您感到困惑的是类型。 struct node 单独是一种类型,而不是变量。在struct node myNode中,myNodetype struct node的变量,在struct node *np中,nptype pointer to struct node的变量。
【解决方案2】:

这里没有 malloc。 hi 指针指向未定义的东西。 hi->下一个。

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

我认为你不懂指针。

【讨论】:

  • 我混淆了通用指针和指向结构的指针。 int *a;
  • 这里,a指向一个整数类型,就像我定义了一个指向结构节点的指针,所以它应该指向那个结构并且已经为它创建了内存
【解决方案3】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-15
    • 1970-01-01
    • 2015-07-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多