C语言 何时以及为何使用 malloc



好吧,我不明白何时以及为什么需要使用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;时需要分配内存?

malloc用于

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

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

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

请看一下手册页 malloc(3(。

当您

需要分配必须在当前块的执行生命周期之后存在的对象(其中返回时复制也会很昂贵(或如果您需要分配大于该堆栈大小的内存(即,3 MB 本地堆栈数组是一个主意(时,您可以使用 malloc

在 C99 引入 VLA 之前,您还需要它来执行动态大小阵列的分配。但是,创建动态数据结构(如树、列表和队列(需要它,这些结构被许多系统使用。可能还有更多原因;这些只是少数。

稍微扩展一下示例的结构,请考虑以下情况:

#include <stdio.h>
int main(int argc, const char *argv[]) {
    typedef struct {
        char *name;
        char *sex;
        char *insurance;
        int age;
        int yearInSchool;
        float tuitionDue;
    } student;
    // Now I can do two things
    student p;
    // Or
    student *p = malloc(sizeof *p);
}

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

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

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

大小

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

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

范围

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

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

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

有关更多详细信息,请阅读此内容。

更改大小 ( realloc (

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

错误检测

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

将来对字符串内容进行更改

如果您创建像char *some_memory = "Hello World";这样的字符串,则无法执行some_memory[0] = 'h';因为它存储为字符串常量,并且存储的内存是只读的。如果您改用 malloc,则可以稍后更改内容。有关更多信息,请查看此答案。

有关可变大小数组的更多详细信息,请查看此内容。

> malloc = Memory ALLOCation

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

Malloc 在 C 语言中做了完全相同的事情。它需要一个参数,需要分配的内存大小,并返回一个指针变量,该变量指向您在内存中创建的整个内存块的第一个内存块。例-

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

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

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

在这个例子中,它似乎确实毫无用处。

但是现在假设您正在使用套接字或文件 I/O,并且必须从可变长度读取数据包,您只能在运行时确定。或者,当使用套接字并且每个客户端连接都需要服务器上的一些存储空间时。你可以创建一个静态数组,但这会给你一个客户端限制,这将在编译时确定。

相关内容

  • 没有找到相关文章

最新更新