malloc/free为何配对使用?

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

为什么需要 mallocfree

在 C 语言中,变量存储在内存的不同区域,主要有:

c语言malloc free
(图片来源网络,侵删)
  1. :存放局部变量、函数参数等,它的特点是自动分配和释放,当函数被调用时,栈空间为变量分配;函数返回时,这些空间自动被回收。大小在编译时确定,运行时无法改变。
  2. 全局/静态区:存放全局变量和静态变量,它的生命周期是整个程序运行期间。
  3. :这是一块自由内存区域,程序可以在运行时根据需要,从堆中申请任意大小的内存,这块内存的生命周期由程序员自己控制,不会自动释放

mallocfree 就是用来管理堆内存的。

  • malloc (Memory Allocation):从堆中分配一块指定大小的内存。
  • free:释放一块由 malloc(或其他类似函数)分配的堆内存,将其归还给系统,以便后续使用。

malloc 函数

函数原型

#include <stdlib.h> // 必须包含的头文件
void *malloc(size_t size);

参数

  • size_t size:你需要分配的内存大小,以字节为单位。

返回值

  • 成功时:返回一个指向分配内存块起始地址void* 指针。void* 是一个通用指针,可以转换为任何类型的指针。
  • 失败时:如果堆内存不足,无法满足请求,malloc 会返回 NULL 指针。

工作原理

malloc 会向操作系统请求一块连续的内存,如果请求成功,它返回这块内存的地址;如果失败,返回 NULL

使用示例

#include <stdio.h>
#include <stdlib.h>
int main() {
    int *ptr; // 声明一个整型指针
    // 1. 分配内存
    // 请求 sizeof(int) 字节的内存,通常是一个整型的大小(4 字节)
    ptr = (int *)malloc(sizeof(int));
    // 2. 检查分配是否成功
    if (ptr == NULL) {
        printf("内存分配失败!\n");
        return 1; // 返回错误码
    }
    // 3. 使用分配的内存
    *ptr = 100;
    printf("ptr 指向的值是: %d\n", *ptr);
    // ... 在这里使用 ptr ...
    // 4. 释放内存
    free(ptr);
    // 5. 将指针置为 NULL (好习惯)
    ptr = NULL;
    return 0;
}

free 函数

函数原型

#include <stdlib.h>
void free(void *ptr);

参数

  • void *ptr:一个指向由 malloccallocrealloc 分配的内存块的指针。

作用

  • 释放 ptr 指向的堆内存。
  • 非常重要free 只会释放内存本身,不会改变指针 ptr 的值ptr 仍然指向那块已经被释放的内存地址,这种指针被称为“悬垂指针”。

为什么必须 free

如果不释放不再使用的堆内存,会导致内存泄漏,随着程序的运行,可用的堆内存会越来越少,最终可能导致程序崩溃,长期运行的程序(如服务器、嵌入式系统)中的内存泄漏是致命的。


关键注意事项和最佳实践

总是检查 malloc 的返回值

忘记检查 malloc 是否返回 NULL 是一个非常常见的错误,在尝试使用指针之前,必须确保它不是 NULL

c语言malloc free
(图片来源网络,侵删)
int *arr = (int *)malloc(100 * sizeof(int));
if (arr == NULL) { // 必须检查!
    // 处理错误
}

配对使用 mallocfree

mallocfree 必须成对出现,有多少次 malloc,就应该有多少次对应的 free,最好在 malloc 后立即规划好在哪里 free

只能 free 由动态分配函数返回的指针

不要尝试 free 栈上的变量、全局变量或不是由 malloc 系列函数分配的内存,这会导致未定义行为,通常是程序崩溃。

int x = 10;
int *ptr_stack = &x;
free(ptr_stack); // 错误!不要这样做!

只能 free 一次

对同一块内存 free 两次会导致双重释放,这也是未定义行为,通常会引起程序崩溃。

int *ptr = (int *)malloc(sizeof(int));
free(ptr);
// ... 其他代码 ...
free(ptr); // 错误!双重释放!

释放后将指针置为 NULL (防御性编程)

free(ptr) 后,ptr 变成了悬垂指针,如果你不小心再次使用它(*ptr = 5;),就会导致内存访问错误,一个很好的习惯是 free 后立即将指针设为 NULL

int *ptr = (int *)malloc(sizeof(int));
// ... 使用 ptr ...
free(ptr);
ptr = NULL; // ptr 是 NULL,再次使用前检查 if (ptr) 就可以避免错误

不要越界访问

动态分配的内存有明确的大小,你必须确保你的代码不会写入超出这个范围的内存,否则会破坏其他数据,导致程序行为异常或崩溃。

int *arr = (int *)malloc(10 * sizeof(int)); // 分配了 10 个 int 的空间
arr[10] = 123; // 错误!索引范围是 0 到 9,越界访问了!

malloc 的亲戚们

malloc 是一个家族,还有其他几个类似的函数:

函数 功能 malloc 的区别
malloc 分配指定字节数的内存 不初始化,内存中是垃圾值。
calloc 分配指定数量和大小的内存,并初始化为 0 参数是 num_elementselement_size
2. 会将分配的内存全部清零。
realloc 重新调整一块已分配内存的大小 可以扩大或缩小内存,如果扩大,新增加的部分不会被初始化,如果内存位置改变,realloc 会自动 free 旧内存并返回新内存的地址。

calloc 示例

// 分配一个能容纳 5 个 double 的数组,并全部初始化为 0.0
double *scores = (double *)calloc(5, sizeof(double));
if (scores != NULL) {
    printf("scores[0] = %f\n", scores[0]); // 输出 0.000000
}
// ...
free(scores);
scores = NULL;

realloc 示例

int *arr = (int *)malloc(5 * sizeof(int));
// ... 填充 arr ...
// 假设现在需要空间变大为 10
int *temp = (int *)realloc(arr, 10 * sizeof(int));
if (temp != NULL) {
    arr = temp; // realloc 成功,更新指针
    // ... 现在可以使用 arr[0] 到 arr[9] ...
} else {
    // realloc 失败,原内存 arr 仍然有效
    printf("内存重新分配失败!\n");
}
// ...
free(arr);
arr = NULL;

函数 作用 关键点
malloc 从堆分配内存 必须检查返回值是否为 NULL
free 释放堆内存 必须与 malloc 配对使用
calloc 分配并清零内存 适用于数组,自动初始化为 0
realloc 调整已分配内存大小 注意处理返回值,可能内存地址会变

掌握 mallocfree 是 C 语言编程中一项核心技能,它们赋予了程序极大的灵活性,但也带来了责任。谁申请,谁释放;申请多少,释放多少;释放之后,指针置空,遵循这些原则,可以避免绝大多数与动态内存相关的错误。

-- 展开阅读全文 --
头像
C语言Hello World如何运行?
« 上一篇 02-08
C语言system(cls)如何实现清屏功能?
下一篇 » 02-08

相关文章

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

目录[+]