为什么要在结构体中使用malloc?

12

为什么我要使用malloc,当同样的工作可以不使用malloc完成,如下所示...

#include <stdio.h>
#include <conio.h>

struct node {
    int data;
    struct node *l;
    struct node *r;
};

int main(){
    //Case 1
    struct node n1;
    n1.data = 99;
    printf("n1 data is %d\n", n1.data);

    //Case 2
    struct node *n2 = (struct node *) malloc (sizeof(struct node));
    n2 -> data = 4444;
    printf("n2 data is:%d\n",n2 -> data);
    free(n2);

    return (0);
}
  1. 我很难理解未初始化到内存位置的n1如何能够存储数据(99)。
  2. 何时使用case 1,何时使用case 2。
5个回答

12

为什么我可以在没有使用malloc的情况下完成相同的任务,

你使用malloc来在堆上分配内存,而不使用malloc,则将结构体放置在堆栈内存中。

我很难理解未初始化到内存位置的n1如何能够存储数据(99)。

无论是否初始化,当你赋值数据n1.data = 99;时,它都会被存储。

2)何时使用情况1和何时使用情况2

当你知道将在受限范围内使用该结构对象,并且不会在其范围之外引用结构数据时,使用情况1。

当你将在多个地方使用结构体,并愿意手动(并小心地!)管理其内存时,请使用情况2。这种方法的优势在于,你可以在程序作用域的某个部分创建并初始化结构体,然后创建指针并传递指针,因为传递4字节指针比传递结构本身更有效率。


您是我的大师!您的回答非常精准,解决了我脑海中的每一个问题!真希望我能给您投1000票哈哈...非常感谢您。 - David Prun
1
"4字节指针比起其他方式更加高效",不仅如此 - 它可以在寄存器中传递,而不必在内存中复制。 - Jonathon Reinhart

4
int main() {
    struct node n1;
    n1.data = 99

这将在主函数的栈框架中预留与结构体节点大小相当的空间。这被称为局部变量,仅存在于主函数的上下文中。
struct node *n2 = (struct node *) malloc (sizeof(struct node));

这是在堆上的分配。无论您处于什么函数上下文中,该内存都存在。通常称为“动态分配”。
这些“node”结构是链接列表的基础,可以随意添加、删除、重新排序等。
另请参阅:

3
在第一种情况下,内存在堆栈上分配。当变量n1超出范围时,内存被释放。
在第二种情况下,内存在堆上分配。您必须明确释放内存资源(就像使用free一样)。
经验法则可以是,对于有限大小的本地临时数据结构,您使用堆栈分配的内存(堆栈仅是计算机内存的一部分,因平台而异)。对于要持久存在或较大的数据结构,请使用堆。
谷歌搜索stack and heap将为您提供更多信息。

2

您的数据类型类似于树中的节点。使用 malloc 分配树节点的两个主要原因是:

  1. 分配任意数量的节点。通常情况下,树节点的数量将是一个运行时值。因此,不可能为这些节点声明正确数量的本地变量,因为所有本地变量都必须在编译时声明。同时,malloc 可以在运行时调用多次,根据需要分配尽可能多的节点对象。

  2. 确保节点在本地对象生命周期结束时(即在块结束时)不会被自动销毁。由 malloc 分配的对象将永久存在,直到您通过调用 free 显式地销毁它们。这种对象将超越块边界和函数边界。局部对象无法实现这样的功能,因为局部对象在其块结束时会自动销毁。

您的代码示例并未依赖于动态分配的任何优点,因为它并没有真正创建一个真正的树。它只声明了一个单一的节点。但是,如果您尝试使用运行时节点数构建完整的树,则会立即意识到无法通过声明节点作为本地对象来完成。您将不可避免地必须使用 malloc 分配节点。

您的“未初始化到内存位置的 n1 如何能够存储数据”的问题可能是由某些混淆引起的。 struct node n1; 是一个对象定义,这意味着它为 n1 分配了一个内存位置。这正是对象定义的目的。


1
通常只有在应用程序运行之前不知道需要多少内存时,才会使用malloc。
您的代码是正确的,但是无法动态分配内存。如果您想将测量值保存在node.date中,并且不知道要捕获多少个测量值,那么您必须在每次进行测量时分配一些新的内存。
如果您在运行时之前(直接在代码中)定义了所有节点,则无法保存比之前定义的更多的测量值。
搜索c中的链表,您会找到一些很好的示例。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接