【问题标题】:When and why to use malloc?何时以及为何使用 malloc?
【发布时间】:2020-07-22 03:58:25
【问题描述】:

好吧,我不明白何时以及为什么需要使用 malloc 分配内存。

这是我的代码:

#include <stdlib.h>

int main(int argc, const char *argv[]) {

  typedef struct {
    char *name;
    char *sex;
    int age;
  } student;


  //Now I can do two things
  student p;

  //or
  student *ptr = (student *)malloc(sizeof(student));

  return 0;
}

我只能使用student p;,为什么还要分配内存?

【问题讨论】:

  • 阅读一本不错的 C 编程书籍。它将比我在几分钟内解释的更好更快地解释堆分配的内存。
  • 你必须了解堆内存和栈内存的区别,看看这个问题:stackoverflow.com/questions/79923/…
  • 别忘了在malloc/calloc 等之后致电free...

标签: c malloc dynamic-memory-allocation


【解决方案1】:

当您需要分配必须存在于当前块执行生命周期之外的对象时(其中返回时复制也很昂贵),或者如果您需要分配大于该堆栈的大小(即:3mb 的本地堆栈数组是一个的想法)。

在 C99 引入 VLA 之前,您还需要它来执行动态大小的数组的分配,但是,它需要用于创建动态数据结构,如树、列表和队列,许多系统。可能还有很多原因,这些只是其中的一小部分。

【讨论】:

  • 词法范围和存储持续时间是两个不同的东西。一个对象可以有块范围和静态存储持续时间。
  • @ouah:那么它就不会是堆栈分配的对象,这就是我所指的。
  • 在 C99 之前,您可以使用 alloca。除此之外,这是最正确的答案,应该标记为解决方案。
【解决方案2】:

malloc 用于动态内存分配。如前所述,它是动态分配,这意味着您在运行时分配内存。例如,当您不知道编译期间的内存量时。

一个例子应该清楚这一点。假设您知道最多有 20 名学生。因此,您可以创建一个包含 20 个静态元素的数组。您的阵列最多可容纳 20 名学生。但是,如果您不知道学生人数怎么办?假设第一个输入是学生人数。它可以是 10、20、50 或其他任何值。现在您将输入 n = 运行时的学生人数,并使用 malloc 动态分配那么多内存。

这只是一个例子。像这样需要动态分配的情况很多。

查看手册页 malloc(3)

【讨论】:

  • 仅仅因为不知道编译时需要多少内存,并不意味着必须涉及堆。
  • @Matt Joiner,这是一个例子。如果您认为这值得投反对票,那么我无话可说。
  • @Matt Joiner,稍微编辑了答案。可能现在听起来更好。
  • 这个答案没有提到 malloc 的非常重要的用途,它分配的内存超出了当前块执行的生命周期。
【解决方案3】:

malloc = Memory ALLOCation.

如果您使用过其他编程语言,您可能使用过 new 关键字。

Malloc 在 C 中做同样的事情。它接受一个参数,需要分配多大的内存,它返回一个指针变量,指向整个内存块的第一个内存块,你在记忆。示例 -

int *p = malloc(sizeof(*p)*10);

现在,*p 将指向内存中保留的连续 10 个整数块中的第一个块。

您可以使用++-- 运算符遍历每个块。

一切顺利。

【讨论】:

  • 你的意思是连续的10个整数块?
【解决方案4】:

在这个例子中,它确实看起来毫无用处。但是现在假设您正在使用套接字或文件 IO,并且必须从可变长度读取数据包,您只能在运行时阻止。或者当使用套接字时,每个客户端连接都需要在服务器上进行一些存储。您可以创建一个静态数组,但这会给您一个客户端限制,这将在编译时受到阻碍。

【讨论】:

  • 可变长度数组可以很好地存储在堆栈上。变长数组不是使用堆的理由。
【解决方案5】:

稍微扩展示例的结构,考虑一下:

#include <stdio.h>

int main(int argc, const char *argv[]) {

typedef struct {
 char* name;
 char* sex;
 char* insurace;
 int age;
 int yearInSchool;
 float tuitionDue;
}student;


//Now I can do two things
student p;

//or
student *p = malloc(sizeof *p);

}

C a 是隐式按值而不是按引用传递的语言。在这个例子中,如果我们将“p”传递给一个函数来做一些工作,我们将创建整个结构的副本。这会使用额外的内存(特定结构需要的总空间),速度较慢,并且可能无法很好地扩展(稍后会详细介绍)。但是,通过传递 *p,我们不会传递整个结构。我们只在内存中传递一个引用这个结构的地址。传递的数据量更小(指针大小),因此操作更快。

现在,知道了这一点,想象一个程序(如学生信息系统)必须创建和管理数千甚至数万的记录集。如果按值传递整个结构,则对一组数据进行操作将花费更长的时间,而不是仅传递指向每条记录的指针。

【讨论】:

    【解决方案6】:

    让我们尝试从不同的方面来解决这个问题

    尺寸

    malloc 允许您分配比仅使用student p;int x[n]; 分配的内存空间大得多的内存空间。原因是malloc在堆上分配空间,而另一个在堆栈上分配空间

    C 编程语言以静态、自动或动态方式管理内存。静态持续时间变量通常与程序的可执行代码一起分配在主内存中,并在程序的生命周期内持续存在;自动持续时间变量在堆栈上分配,并随着函数的调用和返回来来去去。对于静态持续时间和自动持续时间变量,分配的大小必须是编译时常量(可变长度自动数组[5] 的情况除外)。如果直到运行时才知道所需的大小(例如,如果从用户或磁盘文件中读取任意大小的数据),那么使用固定大小的数据对象是不够的。 (from Wikipedia)

    范围

    通常,声明的变量会在声明它的块之后被删除/释放(它们在堆栈上声明)。另一方面,使用malloc 分配内存的变量会一直保留到手动释放它们为止。

    这也意味着您不可能在函数中创建变量/数组/结构并返回其地址(因为它指向的内存可能会被释放)。编译器还会尝试通过发出警告来警告您:

    警告 - 与返回的局部变量“匹配”相关的堆栈内存地址

    更多详情read this

    更改大小 (realloc)

    正如你可能已经猜到的那样,通过正常方式是不可能的

    错误检测

    如果内存无法分配:正常方式可能会导致您的程序终止,而malloc 将返回一个NULL,可以在您的程序中轻松捕获和处理

    将来更改字符串内容

    如果您创建存储像char *some_memory = "Hello World"; 这样的字符串,则不能执行some_memory[0] = 'h';,因为它存储为字符串常量,并且存储在其中的内存是只读的。如果您改用 malloc,您可以稍后更改内容。 欲了解更多信息check this answer

    有关可变大小数组的更多详细信息,请联系look at this

    【讨论】:

    • 什么是“正常方式”?你应该在这里更具体。例如,您不能调整静态或局部变量的大小。
    【解决方案7】:

    当您需要分配必须存在于当前块执行生命周期之外的对象时(其中返回时复制也很昂贵),或者如果您需要分配大于大小的内存,您可以使用 malloc那个堆栈的

    【讨论】:

      猜你喜欢
      • 2012-11-11
      • 2019-02-17
      • 1970-01-01
      • 2015-10-13
      • 1970-01-01
      • 1970-01-01
      • 2023-03-15
      • 2013-06-13
      相关资源
      最近更新 更多