#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 mallocn");
printf("naddress of node is: %p",hi);
printf("naddress of next is: %p",hi->next);
return 0;
}
输出为:
malloc前
节点地址为:0x7ffd37e99e90下一个地址是:0x7ffd37e9a470
为什么两者不相同?
TL;DR
你的代码引发未定义行为,正如Morlacke的回答中已经提到的。除此之外,你似乎在理解指针的工作方式上有问题。参考资料中的教程。
首先,从你的评论
当你说有内存分配给ip
在这种情况下:
int i = 10;
int *ip;
ip = &i;
结果是:
- 您声明了一个名为
i
的int
变量并将值10
赋给它。在这里,计算机在堆栈上为这个变量分配内存。比如地址0x1000
。所以现在地址0x1000
有内容10
。 然后声明一个名为 - 当你分配
ip = &i
时,你是在分配变量i
的地址到变量ip
。现在值变量ip
(指针)的地址是i
的地址。ip
不包含10
-i
的值。把这个赋值看作ip = 0x1000
(实际上不写这个代码)。- 要使用指针获得值
10
,您必须执行*ip
-这称为指针解引用。当你这样做时,计算机将访问指针所保存的地址的内容。在这种情况下,计算机将访问i
地址上的内容,即10
。可以这样想:get the contents of address 0x1000
。 - 要使用指针获得值
ip
的指针,类型为int
。计算机为指针分配内存。(这很重要,见下文解释)。你的指针在地址,比如,0x2000
。这段代码之后的内存是这样的:
VALUE : 10 | 0x1000 |
VARIABLE : i | ip |
ADDRESS : 0x1000 | 0x2000 |
指针指针是c语言中的一种特殊类型的变量。你可以把指针看作是类型化变量,其中保存地址. 你的计算机在堆栈上为指针分配的空间取决于你的架构-在32bit
机器上,指针将占用4字节;在64bit
机器上,指针占用8字节。只有计算机为指针()分配的内存有足够的空间存储地址) .
然而,指针保存着内存地址,所以你可以让它指向某个内存块…比如从malloc返回的内存块.
因此,记住这一点,让我们看看你的代码:
NODE *hi;
printf("nbefore mallocn");
printf("naddress of node is: %p",hi);
printf("naddress of next is: %p",hi->next);
- 声明一个指向
NODE
的指针称为hi
。假设变量hi
的地址是0x1000
,而该地址的内容是是任意的——你没有初始化它,所以它可以是从0到a的任何值。。 然后,当您在
printf
中打印hi
时,您正在打印该地址0x1000
的内容…但你不知道里面有什么……然后取消对hi
变量的引用。你告诉计算机:访问ThunderCat的内容并打印变量next
的值. 现在,我不知道ThunderCats内部是否有变量,也不知道它们是否喜欢被访问……这是未定义行为。而且很糟糕!修改:
NODE *hi = malloc(sizeof NODE);
printf("&hi: %pn", &hi);
printf(" hi: %pn", 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) : %pn", &hi);
printf("Contents of hi : %pn", hi);
printf("Address of next(&next): %pn", &(hi->next));
printf("Contents of next : %pn", hi->next);
printf("Address of id : %pn", &(hi->id));
printf("Contents of id : %dn", 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
在栈上。它所指向的块在堆上。id
的地址与内存块相同(因为它是结构的第一个元素)。next
的地址从id
的8个字节,当它应该只有4(毕竟int
只有4个字节长)-这是由于内存对齐。next
的内容是hi
所指向的同一块。- 为
hi
指针本身"分配"的内存量是8字节,因为我正在64bit
上工作。这就是它所拥有和需要的空间。 - 总是在
malloc
之后的free
。避免内存泄漏 永远不要为了学习以外的目的而写这样的代码。
注意:当我说"分配给指针的内存"时,我的意思是当堆栈框架设置后声明指针时,计算机在堆栈上为它分隔的空间。
引用- SO:如何定义未定义行为
- SO:我是否转换malloc的结果
- SO:堆栈和堆是什么,在哪里? 指针基础
- 指针算术 C -内存管理
- 内存:堆栈vs堆 内存管理
- C结构包装的失落艺术将告诉你关于结构,对齐,包装等…
这里没有malloc。Hi指针指向未定义的东西。Hi ->下一个相同。
关于这个问题。为什么呢?
我认为你不理解指针。
因为next是指针类型,它指向0x7ffd37e9a470。如果输出地址If next &(hi->next),可以看到hi和hi->next的差值都是2(因为int id是第一个元素)。