C 库中的 malloc() 函数及其示例

⚡ 智能摘要

C 语言中的 malloc() 函数会在运行时在堆上预留一块内存,并返回指向其第一个字节的 void 指针,从而允许程序请求大小未知的存储空间,直到代码实际执行为止。

  • 🧠 运行时分配: malloc() 在编译时无法确定所需内存大小的情况下,会在执行期间预留内存。
  • 📦 语法: cast_type 指针接收 malloc(byte_size),通常使用 sizeof 来分配大小,以实现可移植性。
  • ⚠️ 空值检查: 失败的请求会返回 NULL 指针,因此在解引用之前请验证结果。
  • 指针运算: 该块是连续的,因此使用 + 而不是 ++ 来访问数组元素。
  • 🧹 释放内存: 使用 free() 释放每个内存块,以防止内存泄漏和悬空指针。
  • 🤖 人工智能辅助: AI 助手和 GitHub Copilot 会草拟 malloc() 调用并标记缺失的 free() 语句。

C 语言中的 malloc() 函数

C 语言中的 malloc 是什么?

malloc() 函数代表内存分配。它是一个用于动态分配内存块的函数。它保留指定大小的内存空间并返回指向内存位置的空指针。返回的指针通常是 void 类型。这意味着我们可以将 malloc 函数分配给任何指针。

C 语言中的 malloc 是什么

句法

ptr = (cast_type *) malloc (byte_size);

在这里,

  • ptr 是 cast_type 的指针。
  • malloc 函数返回指向分配的 byte_size 内存的指针。
Example: ptr = (int *) malloc (50)

当该语句执行成功后,会保留50字节的内存空间,保留空间第一个字节的地址赋给int类型的指针ptr。

考虑 malloc 实现的另一个例子:

#include <stdlib.h>
int main(){
int *ptr;
ptr = malloc(15 * sizeof(*ptr)); /* a block of 15 integers */
    if (ptr != NULL) {
      *(ptr + 5) = 480; /* assign 480 to sixth integer */
      printf("Value of the 6th integer is %d",*(ptr + 5));
    }
}

输出:

Value of the 6th integer is 480

请注意,这里使用了 sizeof(*ptr) 而不是 sizeof(int),目的是为了在稍后将 *ptr 声明强制转换为不同的数据类型时,使代码更加健壮。

如果内存不足,分配可能会失败。在这种情况下,它会返回一个 NULL 指针。因此,您应该包含代码来检查 NULL 指针。

请记住,分配的内存是连续的,可以将其视为数组。我们可以使用 指针 建议使用加号 (+) 而不是方括号 [ ] 来访问数组元素,因为使用加号 (++) 或加号 (+=) 会改变指针存储的地址。

Malloc 函数还可以用于字符数据类型以及结构等复杂数据类型。

为什么在C语言中使用malloc()?

静态数组和普通变量在程序编译时就固定了它们的大小,这会导致在实际需求较小时浪费空间,而在实际需求较大时直接导致程序崩溃。malloc() 通过在运行时请求内存来解决这个问题,因此程序可以根据接收到的数据量精确地分配缓冲区大小。这种运行时灵活性是内存分配的核心所在。 动态内存分配 在 C。

在几种常见情况下,使用 malloc() 进行动态分配是正确的选择:

  • 在程序运行之前,输入量是未知的,例如读取文件或用户提供的列表。
  • 需要大块内存才能分配有限的内存,因为 malloc() 是从更大的堆中分配的,这会导致有限的栈溢出。
  • 数据的生命周期必须长于创建它的函数,因为堆内存会一直存在,直到被显式释放为止。
  • 程序运行时,结构体和数组需要增长或缩小。

由于保留的数据块是以指针的形式返回的,因此可以在函数之间以低成本传递,而无需复制底层数据。

如何释放 malloc() 分配的内存

malloc() 函数分配的内存位于堆上,不会自动释放。当程序不断分配内存而不释放时,它会逐渐耗尽所有可用内存,这种缺陷被称为内存泄漏。free() 函数会将已分配的内存块释放回系统,以便系统可以重新利用这些空间。

free() 函数接受一个参数,即 malloc() 返回的指针,并一次性释放整个内存块:

int *ptr;
ptr = malloc(10 * sizeof(int));
if (ptr != NULL) {
    /* use the allocated memory here */
    free(ptr);   /* release the block */
    ptr = NULL;  /* avoid a dangling pointer */
}

请遵循以下规则安全地管理动态内存:

  • 对于每个成功的 malloc(),都应调用 free() 一次;对同一个内存块释放两次会导致未定义行为。
  • 释放指针后将其设置为 NULL,以防止其被重新用作悬空指针。
  • 永远不要使用 free() 释放 malloc() 没有返回的指针,包括通过指针运算移位的指针。
  • 在指针超出作用域之前,每次内存分配都必须与相应的内存释放相匹配。

记ping 内存分配和释放的平衡是 C 语言中手动内存管理的核心原则,它可以防止因重复使用已释放的内存而导致的内存泄漏和崩溃。

malloc() 与 calloc():主要区别

malloc() 和 调用() 两者都会分配堆内存,但它们的参数和处理方式有所不同。malloc() 接受一个参数,即总字节数,并且不会初始化内存块的内容,因此在程序写入之前,该内存块会包含不可预测的垃圾值。calloc() 接受两个参数,即元素的数量和每个元素的大小,并在返回指针之前将每个字节清零。

实际上的区别主要体现在以下三点:

  • 初始化:calloc() 会将内存清零,而 malloc() 不会,因此当值无论如何都会被覆盖时,malloc() 的速度会稍微快一些。
  • 论点:你写 malloc(n * size) 但 calloc(n, size) 来保留同一个数组。
  • 使用场景:当需要干净、零化的数据块时,选择 calloc();当优先考虑速度并且需要手动处理初始化时,选择 malloc()。

这两个函数都在 stdlib.h 中声明,失败时都返回 void 指针或 NULL,并且都使用相同的 free() 函数释放内存。

常见问题

在 C 语言中,类型转换是可选的,而且通常不建议这样做,因为 void* 会自动转换为任何对象指针,而显式类型转换可能会掩盖缺少 stdlib.h 头文件的情况。 C++但是,演员阵容是必需的。

返回 NULL 值表示请求失败,通常是由于内存不足。使用指针之前务必先检查其值,因为解引用 NULL 会导致未定义行为,通常会导致程序崩溃。

realloc() 会调整之前由 malloc() 分配的内存块的大小,保持ping 将现有数据缩小到较小尺寸。如果失败,则返回 NULL 并保持原始数据块不变,因此应先将结果赋值给一个临时指针。

当程序使用 malloc() 分配的堆内存没有被 free() 释放时,就会发生内存泄漏。程序会不断占用不再使用的空间,这会导致可用内存逐渐耗尽。

malloc() 函数会在堆上而不是栈上分配内存。堆内存块会一直有效,直到你调用 free() 函数,因此它们的生命周期可以比创建它们的函数更长,这与函数返回时就会消失的自动栈变量不同。

malloc() 是一个库函数,它返回 void*,需要 sizeof 来计算字节数。 C++ new 是一个返回类型化指针并调用构造函数的运算符。malloc() 与 free() 搭配使用,new 与 delete 搭配使用。

是的。AI 代码助手可以自动生成 malloc() 调用、插入空值检查、标记缺失的 free() 调用或内存泄漏,还能解释指针运算。但务必在信任生成的代码之前进行编译和测试。

GitHub 副驾驶 根据描述您意图的注释,建议使用 malloc()、sizeof() 和匹配的 free() 行。 Rev编译前请查看每条关于缺失 NULL 检查和内存泄漏的建议。

总结一下这篇文章: