TL;DR
您的代码会引发未定义的行为,正如Morlacke's Answer 中已经提到的那样。除此之外,您似乎在理解指针的工作方式方面遇到了问题。有关教程,请参阅参考资料。
首先,来自您的 cmets
当您说在这种情况下为ip 分配了内存时:
int i = 10;
int *ip;
ip = &i;
会发生什么:
- 您声明了一个名为
i 的int 变量并将值10 分配给它。在这里,计算机在堆栈上为 this variable 分配内存。比如说,地址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。
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);
- 声明一个指向
NODE 的指针,称为hi。让我们假设这个变量hi 有地址0x1000,并且该地址的内容 是任意的——你没有初始化它,所以它可以是从零到@987654323 的任何值@。
- 然后,当您在
printf 中打印hi 时,您正在打印该地址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 个(毕竟ints 只有 4 个字节长) - 这是由于内存对齐。
-
next 的内容与hi 指向的块相同。
-
hi 指针本身“分配”的内存量为 8 个字节,因为我正在处理 64bit。这就是它拥有和需要的所有房间。
- 总是
free 在malloc 之后。避免memory leaks
- 切勿为学习以外的其他目的编写这样的代码。
注意:当我说“为指针分配的内存”时,我指的是在 Stack Frame 设置之后发生声明时计算机在堆栈上为其分隔的空间。
参考