C 库中的 calloc() 函数及其程序示例

⚡ 智能摘要

C 语言中的 calloc() 函数会在堆上预留多个连续的内存块,并将每个字节初始化为零,返回一个 void 指针,使程序能够在运行时创建干净、可直接使用的数组和数据结构。

  • 🧠 零初始化内存: calloc() 会将每个已分配的字节清除为零,这与 malloc() 不同,malloc() 会留下不可预测的垃圾值。
  • 📦 两个论点: calloc(n, size) 会在一个连续区域中保留 n 个给定大小的块。
  • ⚠️ 空值检查: 分配失败会返回 NULL 指针,因此在使用结果之前请先验证结果。
  • ???? calloc 与 malloc: 对于干净的零数组,请选择 calloc();当速度比初始化更重要时,请选择 malloc()。
  • 🧹 释放内存: 使用 free() 释放每个 calloc() 代码块,以防止内存泄漏。
  • 🤖 人工智能辅助: AI 助手和 GitHub Copilot 会草拟 calloc() 调用并标记缺失的 free() 语句。

C 语言中的 calloc() 函数

C 语言中的 calloc 是什么?

C 语言中的 calloc() 函数用于分配多个大小相同的内存块。它是一个动态内存分配函数,可以为数组、结构体等复杂数据结构分配内存空间,并返回指向该内存的空指针。calloc 代表连续分配。

Malloc 函数 用于分配单块内存空间,而 C 语言中的 calloc 函数用于分配多块内存空间,C 语言中 calloc 分配的每个块大小相同。

为什么C语言中使用calloc()函数?

普通变量和固定大小数组在程序编译时会锁定其维度,这在需要较少元素时会浪费空间,而在需要更多元素时则会直接导致程序崩溃。calloc() 通过在运行时预留内存来消除这种限制,并且与 malloc() 不同,它会在将内存块返回之前将每个字节清零。因此,当程序需要为大小仅在代码运行时才确定的数组或结构体分配一块干净、可预测的内存区域时,calloc 是自然而然的选择。

使用 calloc() 进行动态分配适用于以下几种常见情况:

  • 应该从零开始的数值数组,例如计数器、直方图或累加器。
  • 数据结构中残留的垃圾值会导致微妙且难以察觉的问题。trac虫子。
  • Buffer其长度取决于用户输入或程序运行时读取的文件。
  • 由于 calloc() 从更大的堆中读取数据,因此对于有限的栈来说,数据块太大。

由于保留块是连续的且已清零,因此可以立即将其视为一个可直接使用的数组,而无需单独的初始化循环。

calloc() 语法:

ptr = (cast_type *) calloc (n, size);
  • 上面C语言中calloc的语句示例用于分配n个大小相同的内存块。
  • 分配内存空间后,所有字节都被初始化为零。
  • 指针 返回当前分配的内存空间的第一个字节。

每当分配内存空间时出现错误(例如内存不足)时,就会返回一个空指针,如下面的 calloc 示例所示。

如何使用 calloc

下面的 C 语言 calloc 程序计算算术序列的总和。

#include <stdio.h>
    int main() {
        int i, * ptr, sum = 0;
        ptr = calloc(10, sizeof(int));
        if (ptr == NULL) {
            printf("Error! memory not allocated.");
            exit(0);
        }
        printf("Building and calculating the sequence sum of the first 10 terms \ n ");
        for (i = 0; i < 10; ++i) { * (ptr + i) = i;
            sum += * (ptr + i);
        }
        printf("Sum = %d", sum);
        free(ptr);
        return 0;
    }

C 示例中 calloc 的结果:

 
Building and calculating the sequence sum of the first 10 terms
Sum = 45

calloc() 和 malloc() 的区别

calloc() 和 malloc() 都会在堆上预留内存,并且都会返回一个 void 指针,或者在失败时返回 NULL,但它们在三个实际方面有所不同,这决定了应该使用哪一个。

  • 初始化:calloc() 将新块中的每个字节设置为零,而 malloc() 则不初始化内容,因此 malloc() 块会保存不可预测的垃圾,直到程序写入它。
  • 参数:calloc() 接受两个参数,元素的数量和每个元素的大小,写作 calloc(n, size);malloc() 接受一个参数,总字节数,写作 malloc(n * size)。
  • 速度:malloc() 的速度略快,因为它跳过了清零步骤,因此立即覆盖内存的代码通常会更喜欢它。

这两个函数都在 stdlib.h 中声明,并且都使用同一个 free() 函数释放内存。如果需要干净的、清零的内存块,请选择 calloc();如果更注重速度并且程序自行处理初始化,则选择 malloc()。

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

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

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

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

请遵循以下规则以安全地管理 calloc() 内存:

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

由于 calloc() 和 malloc() 都从同一个堆中分配内存,因此它们的释放机制相同:每次成功分配后调用一次 free(),之后不得再访问该内存块。ping 平衡地分配和释放内存是 C 语言中手动内存管理的核心习惯,它可以防止内存泄漏和因重复使用已释放的内存而导致的崩溃。

常见问题

calloc() 函数在标准库头文件 stdlib.h 中声明,因此需要添加 #include 指令。在源文件顶部。如果没有它,编译器可能会警告存在隐式声明,并错误读取返回的指针。

当堆内存不足以满足请求时,calloc() 会返回一个空指针(NULL),而不是一个有效的地址。在使用返回值之前,务必将其与 NULL 进行比较,因为解引用 NULL 会导致未定义行为,通常会导致程序崩溃。

是的。calloc() 函数可以处理任何类型的数据,包括结构体和结构体数组,只需传入元素数量和 sizeof(struct) 参数即可。它会将每个元素的值清零,从而提供一个干净的初始状态,无需手动初始化循环。

是的。`realloc()` 函数接受 `calloc()` 或 `malloc()` 返回的任何指针,并根据指针指向的内存块大小进行扩展或缩减,同时保留现有数据。`realloc()` 添加的新字节不会被清零,因此如果需要,请自行初始化。

结果取决于具体实现:calloc() 可能返回 NULL 或一个无法解引用但可以安全地传递给 free() 的唯一指针。无论哪种结果都应视为“无可用内存”,并避免从中读取数据。

calloc() 函数会预留一块足够大的连续内存区域,容纳所有请求的元素,这些元素像数组单元格一样背靠背排列。其名称也反映了这种连续的、已清空的内存块,使得指针运算能够可靠地遍历内存。

是的。AI 代码助手会生成 calloc() 调用、添加空值检查、标记缺失的 free() 调用或内存泄漏,还会解释指针运算。在将生成的代码投入生产环境之前,务必先编译并测试。

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

总结一下这篇文章: