malloc在C语言中如何分配内存?

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

什么是 malloc

malloc 是 "memory allocation"(内存分配)的缩写,它是一个标准库函数,定义在头文件 <stdlib.h> 中。

c语言中的malloc
(图片来源网络,侵删)

核心功能: 在程序的 上申请一块指定大小的连续内存空间,并返回一个指向这块内存起始地址的 void* 类型的指针。

为什么需要 malloc C 语言中的变量通常在 上分配内存,栈内存的特点是:

  • 自动管理:函数调用时分配,返回时释放。
  • 大小固定:编译时确定。
  • 生命周期短。

但有些情况下,我们需要更灵活的内存管理:

  • 数据大小不确定: 比如你需要存储用户输入的数据,但不知道用户会输入多少。
  • 数据生命周期需要超过函数范围: 比如一个函数创建了一个数组,但需要将这个数组返回给调用者使用。
  • 需要大量内存: 栈空间通常很小,无法容纳大型数据结构(如大数组、大图等)。

这时,malloc 就派上用场了,它可以在上申请内存,堆的内存空间大,并且由程序员手动管理。

c语言中的malloc
(图片来源网络,侵删)

malloc 的函数原型

void* malloc(size_t size);

参数:

  • size_t size: 你想要分配的内存大小,以字节为单位,这是一个无符号整型。

返回值:

  • 成功时: 返回一个 void* 类型的指针,指向分配的内存块的起始地址。
  • 失败时: 如果堆空间不足以满足请求,malloc 会分配失败,并返回 NULL 指针。

关键点:

  • void* 指针:* `void是一种“通用指针”,它可以指向任何类型的数据,你不能直接对void指针进行解引用(如ptr)或指针算术运算,因为你不知道它指向的数据类型是什么,在使用malloc` 后,必须**将返回的指针强制转换为你需要的类型。
  • 不初始化: malloc 只负责分配内存,不会对分配的内存进行初始化,这块内存里是“垃圾值”,即之前使用这块内存时留下的数据,你必须手动将值写入其中。

如何使用 malloc?(一个完整的例子)

下面是一个使用 malloc 的标准流程和示例代码。

c语言中的malloc
(图片来源网络,侵删)
#include <stdio.h>
#include <stdlib.h> // 必须包含这个头文件才能使用 malloc
int main() {
    int n;
    int *ptr; // 声明一个整型指针
    // 1. 确定需要多少内存
    printf("请输入要存储的整数个数: ");
    scanf("%d", &n);
    // 2. 调用 malloc 分配内存
    // 分配 n 个 int 大小的内存空间
    // sizeof(int) 获取一个 int 类型的大小(通常是4字节)
    // 将返回的 void* 指针强制转换为 int* 指针
    ptr = (int*)malloc(n * sizeof(int));
    // 3. 检查 malloc 是否成功(极其重要!)
    if (ptr == NULL) {
        printf("内存分配失败!\n");
        return 1; // 返回非零值表示程序异常终止
    }
    // 4. 使用分配的内存
    printf("请输入 %d 个整数:\n", n);
    for (int i = 0; i < n; i++) {
        scanf("%d", &ptr[i]); // 像使用普通数组一样使用指针
    }
    printf("你输入的整数是:\n");
    for (int i = 0; i < n; i++) {
        printf("%d ", ptr[i]);
    }
    printf("\n");
    // 5. 释放内存(至关重要!)
    // 使用完动态分配的内存后,必须用 free() 释放它
    free(ptr);
    // 6. 将指针置为 NULL(良好的编程习惯)
    // 这可以防止产生“悬垂指针”(Dangling Pointer)
    ptr = NULL;
    return 0;
}

malloc 的关键注意事项

1 检查返回值是否为 NULL

这是 malloc 使用中最重要也最容易被忽略的一点,如果内存分配失败,程序继续使用 NULL 指针会导致未定义行为,通常是程序崩溃(段错误 Segmentation Fault)。

2 必须手动释放内存 (free)

堆内存不会像栈内存那样自动释放,如果你只分配不释放,会导致内存泄漏,内存泄漏会逐渐耗尽系统的可用内存,最终可能导致程序或整个系统变慢甚至崩溃。

free 的原型:

void free(void* ptr);
  • ptr: 必须是之前由 malloc, calloc, realloc 返回的指针。
  • 释放后,这块内存可以被后续的 malloc 再次使用。
  • 对一个已经 free 过的指针再次 free不安全的(尽管在某些系统上可能无害)。

3 避免 “内存泄漏” 和 “悬垂指针”

  • 内存泄漏: malloc 后没有对应的 free
    int *p = (int*)malloc(sizeof(int) * 100);
    // ... 使用 p ...
    // 忘记了 free(p); // 内存泄漏!
  • 悬垂指针: 对一个指针指向的内存 free 后,没有将指针本身设为 NULL,之后如果再次使用这个指针,就会访问到一块无效的内存,导致未定义行为。
    int *p = (int*)malloc(sizeof(int));
    *p = 10;
    free(p); // p 现在是一个悬垂指针
    // ...
    *p = 20; // 错误!访问了已释放的内存

4 不要超出分配的内存范围

malloc 分配了一块固定大小的内存,你必须确保你的程序不会写入这块内存之外的区域,否则会导致缓冲区溢出,这是非常严重的安全漏洞。

int *arr = (int*)malloc(5 * sizeof(int)); // 只能安全地访问 arr[0] 到 arr[4]
arr[5] = 100; // 越界访问!非常危险!

malloc 相关的其他函数

malloc 通常不是孤立使用的,它有一整套家族函数:

函数 功能 关键区别
malloc(size_t size) 分配 size 字节的未初始化内存。 是垃圾值。
calloc(size_t num, size_t size) 分配 num 个元素,每个元素 size 字节的内存,并将所有位初始化为 0。 会将内存初始化为 0,2. 参数是元素个数和单个元素大小。
*`realloc(void ptr, size_t new_size)`** 重新调整之前通过 malloccalloc 分配的内存块的大小。 可以扩大缩小内存块,2. 如果扩大,新增部分的内容是未定义的,3. 可能会移动内存块到新位置,并返回新的指针。
*`free(void ptr)`** 释放之前分配的内存块。 释放内存,防止泄漏。

realloc 的使用示例:

int *arr = (int*)malloc(5 * sizeof(int));
// ... 使用 arr ...
// 现在需要更多的空间
int *new_arr = (int*)realloc(arr, 10 * sizeof(int));
if (new_arr == NULL) {
    // realloc 失败,原指针 arr 仍然有效
    printf("重新分配失败!\n");
} else {
    // realloc 成功,新的内存块地址在 new_arr
    // 旧的指针 arr 可能已经无效,必须使用 new_arr
    arr = new_arr;
    // ... 现在可以使用 arr[0] 到 arr[9] ...
}
// ...
free(arr);

特性 描述
功能 在堆上申请一块指定大小的连续内存。
头文件 <stdlib.h>
返回值 成功返回 void* 指针,失败返回 NULL
内存未初始化 malloc 不会清零内存,必须手动赋值。
必须释放 使用 free() 释放内存,否则会内存泄漏。
必须检查 检查 malloc 的返回值是否为 NULL
类型转换 使用后通常需要将 void* 转换为具体类型的指针。

malloc 是 C 语言强大而灵活特性的体现,但它也要求程序员有高度的责任心。申请必释放,用前必检查,越界必致命,掌握了 malloc,你就能编写出功能更强大、更复杂的 C 程序。

-- 展开阅读全文 --
头像
织梦农家乐模板好用吗?
« 上一篇 今天
dede地方门户模板如何快速搭建本地化网站?
下一篇 » 今天

相关文章

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

目录[+]