malloc与calloc有何区别?

99ANYc3cd6
预计阅读时长 14 分钟
位置: 首页 C语言 正文

为什么需要动态内存分配?

在 C 语言中,变量的内存分配方式主要有两种:

c语言 malloc calloc
(图片来源网络,侵删)
  1. 静态内存分配:在编译时确定内存大小,如 int a[100];,大小固定,不能在程序运行时改变。
  2. 动态内存分配:在程序运行时,根据需要向操作系统申请内存,这种方式非常灵活,可以处理数据大小不确定的情况(读取用户输入的未知数量的数据)。

malloccalloc 就是实现动态内存分配的两个标准库函数。


malloc (Memory Allocation)

malloc 的作用是在堆上分配一块指定大小的连续内存空间。

函数原型

#include <stdlib.h> // 或 <malloc.h>
void *malloc(size_t size);

参数

  • size_t size: 你想要分配的内存字节数。

返回值

  • 成功: 返回一个指向分配内存块起始地址void* 指针。void* 是一个通用指针,你可以将它转换为任何类型的指针。
  • 失败: 返回 NULL 指针,如果内存不足或请求为 0,malloc 可能会失败,此时必须检查返回值。

特点

  • 不初始化malloc 分配的内存是未初始化的,里面是“垃圾值”(Garbage Value),你必须手动将值写入这块内存。
  • 只分配指定大小的内存:它只关心你请求的字节数,不关心你用来接收它的指针类型。

使用示例

#include <stdio.h>
#include <stdlib.h>
int main() {
    int n = 5;
    int *ptr;
    // 1. 分配内存
    // sizeof(int) * n 计算总共需要多少字节
    ptr = (int *)malloc(n * sizeof(int)); // 将 void* 转换为 int*
    // 2. 检查分配是否成功
    if (ptr == NULL) {
        printf("内存分配失败!\n");
        return 1; // 退出程序
    }
    printf("malloc 成功分配了 %d 个 int 的内存,\n", n);
    // 3. 使用内存(必须手动初始化)
    for (int i = 0; i < n; i++) {
        ptr[i] = i + 10; // 给每个元素赋值
    }
    // 4. 打印内存内容
    printf("ptr 指向的数组内容: ");
    for (int i = 0; i < n; i++) {
        printf("%d ", ptr[i]);
    }
    printf("\n");
    // 5. 释放内存
    free(ptr); // 释放后,ptr 变成“野指针”,最好立即置为 NULL
    ptr = NULL;
    return 0;
}

calloc (Contiguous Allocation)

calloc 的作用是在堆上分配一块内存,并将其所有位初始化为 0

函数原型

#include <stdlib.h> // 或 <malloc.h>
void *calloc(size_t num, size_t size);

参数

  • size_t num: 要分配的元素个数
  • size_t size: 每个元素的大小(字节数)。

返回值

  • 成功: 返回一个指向分配内存块起始地址void* 指针。
  • 失败: 返回 NULL 指针。

特点

  • 自动初始化为 0calloc 分配的内存会被清零,这对于数组结构特别有用,可以避免使用未初始化的数据。
  • 参数是元素个数和大小:它的设计更侧重于分配数组。

使用示例

#include <stdio.h>
#include <stdlib.h>
int main() {
    int num_elements = 5;
    int *ptr;
    // 1. 分配内存
    // 分配 5 个 int 大小的内存,并全部初始化为 0
    ptr = (int *)calloc(num_elements, sizeof(int));
    // 2. 检查分配是否成功
    if (ptr == NULL) {
        printf("内存分配失败!\n");
        return 1;
    }
    printf("calloc 成功分配了 %d 个 int 的内存,并初始化为 0,\n", num_elements);
    // 3. 打印内存内容(可以直接看到是 0)
    printf("ptr 指向的数组内容: ");
    for (int i = 0; i < num_elements; i++) {
        printf("%d ", ptr[i]);
    }
    printf("\n");
    // 4. 使用内存(可以直接赋值,因为已经是 0)
    ptr[0] = 100;
    ptr[4] = 200;
    printf("修改后的数组内容: ");
    for (int i = 0; i < num_elements; i++) {
        printf("%d ", ptr[i]);
    }
    printf("\n");
    // 5. 释放内存
    free(ptr);
    ptr = NULL;
    return 0;
}

malloc vs calloc 核心区别

特性 malloc calloc
功能 分配指定字节的内存 分配指定数量和大小的内存,并清零
参数 1 个:总字节数 (size_t size) 2 个:元素个数 (size_t num) 和 元素大小 (size_t size)
内存初始化 不初始化是垃圾值 自动初始化为 0 (全零)
主要用途 分配单个变量或结构体,或对初始化有特殊要求的数组 分配数组,尤其是希望默认值为 0 的数组

重要注意事项

  1. 检查返回值:每次调用 malloccalloc 后,必须检查返回值是否为 NULL,这是防止程序因内存不足而崩溃的关键步骤。
  2. 释放内存:使用 malloc/calloc 分配的内存,在不再使用时,必须使用 free() 函数释放,否则会导致内存泄漏
  3. 避免重复释放:对同一块内存调用 free() 两次是未定义行为,通常会导致程序崩溃。
  4. 释放后置空free(ptr) 只是释放了内存,但指针变量 ptr 本身仍然存在,它仍然指向那块已释放的内存(这被称为“野指针”),为了避免误用,最好在 free 后立即将指针置为 NULLptr = NULL;
  5. 不要越界访问:动态分配的内存有固定的大小,访问超出这个范围的内存(数组越界)会导致未定义行为,可能引发程序崩溃或安全漏洞。
  6. realloc 的补充:如果需要调整已分配内存的大小,可以使用 realloc 函数,它会尝试在原地扩展内存,如果不行,则会分配一块新内存,并将旧数据复制过去,然后释放旧内存。
  • malloc:当你只需要一块内存,并且不关心它初始值是什么(或者你之后会立即覆盖它),或者你只想分配一个单一的结构体时。
  • calloc:当你明确需要分配一个数组,并且希望所有元素的初始值都为 0 时。calloc 在这一点上提供了便利和安全性。

理解并正确使用 malloccalloc 是掌握 C 语言动态内存管理的基石,也是编写健壮、高效 C 程序的必备技能。

c语言 malloc calloc
(图片来源网络,侵删)
c语言 malloc calloc
(图片来源网络,侵删)
-- 展开阅读全文 --
头像
dede织梦多级下拉菜单如何实现?
« 上一篇 12-07
dede5.7免登录接口,如何实现文章通用模型?
下一篇 » 12-07

相关文章

取消
微信二维码
支付宝二维码

目录[+]