gpt4 book ai didi

c - 为什么结构和下一个的地址不同?

转载 作者:行者123 更新时间:2023-11-30 21:17:59 26 4
gpt4 key购买 nike

#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

为什么两者不一样?

最佳答案

TL; DR

Morlacke's Answer中所述,您的代码会引发未定义的行为。除此之外,您似乎在理解指针的工作方式上遇到了问题。请参阅参考资料以获取教程。



首先,根据您的评论

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

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


发生的是:


您声明一个名为 inti变量,并为其分配值 10。在这里,计算机在堆栈上为此变量分配内存。说,在地址 0x1000。所以现在,地址 0x1000具有内容 10
然后,声明一个名为 ip的指针,其类型为 int。计算机为指针分配内存。 (这很重要,请参见下面的说明)。您的指针位于地址,例如 0x2000
分配 ip = &i时,就是将变量 i的地址分配给变量 ip。现在变量 ip的值(您的指针)是 i的地址。 ip不保存值 10- i保留。将此分配视为 ip = 0x1000(实际上不编写此代码)。
要使用指针获取值 10,您必须执行 *ip-这称为解引用指针。当您执行此操作时,计算机将访问指针保存的地址的内容,在这种情况下,计算机将访问 i的地址,即 10。可以将其视为: get the contents of address 0x1000


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

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);



声明指向 NODE的指针,称为 hi。假设该变量 hi具有地址 0x1000,并且该地址的内容是任意的-您没有对其进行初始化,因此它可以是从零到 ThunderCat的任何值。
然后,当您在 hi中打印 printf时,您正在打印该地址 0x1000的内容...但是您不知道其中的内容...可能是任何东西。
然后,您取消引用 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的地址是一个,而它指向的地址是另一个。在此输出上有几件事要注意:


hi在堆栈上。它指向的块在堆上。
id的地址与内存块相同(这是因为它是结构的第一个元素)。
next的地址是 id的8个字节,这时它应该只有4个字节(毕竟所有 int的长度只有4个字节)-这是由于内存对齐所致。
next的内容与 hi指向的块相同。
当我在 hi上工作时,为 64bit指针本身“分配”的内存量为8个字节。这就是它所需要的所有空间。
free之后始终 malloc。避免 memory leaks
除了学习之外,切勿将这样的代码用于其他目的。


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



参考文献


因此: How Undefined is Undefined Behavior
因此: Do I cast the result of malloc
因此: What and where are the stack and heap?
Pointer Basics
Pointer Arithmetic
C - Memory Management
Memory: Stack vs Heap
Memory Management
The Lost Art of C Strucutre Packing会告诉您有关结构,对齐方式,包装等的信息...

关于c - 为什么结构和下一个的地址不同?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32780459/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com