malloc循环如何高效分配内存?

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

核心概念

在循环中使用 malloc 的主要目的是根据循环的次数或条件,动态地创建一系列内存块,你可能需要为每个学生分配一个结构体,或者为每一行数据分配一个字符数组。

c语言malloc循环
(图片来源网络,侵删)

一个简单的示例:分配一个整数数组

假设我们想动态分配一个包含 n 个整数的数组。

#include <stdio.h>
#include <stdlib.h> // 必须包含这个头文件才能使用 malloc
int main() {
    int n = 5;
    int *numbers; // 声明一个整型指针
    // 1. 分配一块连续的内存,可以存放 n 个 int
    // sizeof(int) * n 计算总共需要的字节数
    numbers = (int *)malloc(n * sizeof(int));
    // 2. 检查 malloc 是否成功分配内存
    // malloc 在失败时会返回 NULL 指针
    if (numbers == NULL) {
        printf("内存分配失败!\n");
        return 1; // 返回非零表示错误
    }
    // 3. 使用循环来初始化这块内存
    for (int i = 0; i < n; i++) {
        numbers[i] = i * 10; // 像使用普通数组一样使用指针
        printf("numbers[%d] = %d\n", i, numbers[i]);
    }
    // 4. 释放内存!非常重要!
    // 将之前分配的内存归还给系统
    free(numbers);
    // 5. 将指针设为 NULL,这是一个好习惯,可以防止“悬垂指针”
    numbers = NULL;
    return 0;
}

输出:

numbers[0] = 0
numbers[1] = 10
numbers[2] = 20
numbers[3] = 30
numbers[4] = 40

在循环中为多个对象分配内存(更常见的场景)

这才是 malloc 循环的真正威力所在,我们通常为循环的每一次迭代分配一个独立的内存块。

场景: 我们想存储5个学生的姓名,每个姓名的长度不同。

c语言malloc循环
(图片来源网络,侵删)
#include <stdio.h>
#include <stdlib.h>
#include <string.h> // 使用 strcpy
int main() {
    int num_students = 5;
    char *student_names[num_students]; // 声明一个指针数组,每个元素都是一个 char*
    // 分配阶段:在循环中为每个学生分配内存
    for (int i = 0; i < num_students; i++) {
        // 假设我们为每个名字分配 20 个字符的空间 (+1 给 '\0')
        student_names[i] = (char *)malloc(20 * sizeof(char));
        // 检查分配是否成功
        if (student_names[i] == NULL) {
            printf("为 student_names[%d] 分配内存失败!\n", i);
            // 如果分配失败,我们应该释放之前已经分配的所有内存
            for (int j = 0; j < i; j++) {
                free(student_names[j]);
            }
            return 1;
        }
    }
    // 使用阶段:在循环中写入数据
    strcpy(student_names[0], "Zhang San");
    strcpy(student_names[1], "Li Si");
    strcpy(student_names[2], "Wang Wu");
    strcpy(student_names[3], "Zhao Liu");
    strcpy(student_names[4], "Qian Qi");
    // 打印阶段:在循环中读取数据
    printf("学生名单:\n");
    for (int i = 0; i < num_students; i++) {
        printf("%d: %s\n", i + 1, student_names[i]);
    }
    // 释放阶段:在循环中释放所有分配的内存
    // 这是至关重要的一步,否则会造成严重的内存泄漏!
    printf("\n正在释放内存...\n");
    for (int i = 0; i < num_students; i++) {
        free(student_names[i]); // 释放每个指针指向的内存块
        student_names[i] = NULL; // 将指针置为 NULL
    }
    return 0;
}

输出:

学生名单:
1: Zhang San
2: Li Si
3: Wang Wu
4: Zhao Liu
5: Qian Qi
正在释放内存...

关键点和最佳实践

  1. 检查返回值malloc 并不总是成功,在内存不足时,它会返回 NULL永远不要忽略这个检查,否则解引用一个 NULL 指针会导致程序崩溃(段错误)。

  2. 计算所需大小:使用 sizeof(你的数据类型) 来确保分配了正确数量的字节。malloc(10) 只分配10字节,可能不够放一个整数,而 malloc(10 * sizeof(int)) 则会分配足够存放10个整数的空间。

  3. 释放内存malloc 分配的内存不会自动释放,它存在于程序的堆上,直到你显式地调用 free() 来释放它。忘记 free 是导致内存泄漏最常见的原因,内存泄漏会使程序在长时间运行后消耗越来越多的内存,最终导致系统变慢或崩溃。

    c语言malloc循环
    (图片来源网络,侵删)
  4. 匹配 freemalloc:你用 malloc 分配的内存,必须用 free 来释放,不能用 free 释放静态变量、栈上的变量或其他函数(如 calloc)分配的内存(除非它们是兼容的)。

  5. 避免重复释放千万不要对一个内存块调用两次 free,这会导致“双重释放”错误,同样会引发程序崩溃或未定义行为,将指针置为 NULL (ptr = NULL;) 可以防止这种情况,因为 free(NULL) 是安全的(它什么都不做)。

  6. 不要越界访问:分配了多少内存,就只能使用多少,如果你为一个10个整数的数组分配了空间,就不要尝试访问 array[10],这会导致缓冲区溢出,同样是严重的错误。

常见错误示例

错误1:忘记检查 malloc 的返回值

int *p = (int *)malloc(1000000000 * sizeof(int)); // 尝试分配超大内存
*p = 10; // p 是 NULL,这里会直接导致程序崩溃

错误2:内存泄漏

void function_with_leak() {
    int *p = (int *)malloc(sizeof(int));
    *p = 100;
    // 函数结束时,p 被销毁,但它指向的内存块没有被释放
    // 这块内存就“泄漏”了,再也找不回来
}
int main() {
    for (int i = 0; i < 10000; i++) {
        function_with_leak(); // 每次调用都会泄漏一点内存
    }
    return 0;
}

错误3:双重释放

int *p = (int *)malloc(sizeof(int));
free(p);
free(p); // 第二次 free 是错误的!

在循环中使用 malloc 是C语言中处理动态数据结构(如链表、动态数组、树等)的基础,记住这个黄金法则:

对于每一次 malloc,都应有一次对应的 free

并且始终牢记:

  1. 检查 NULL
  2. 计算正确的 sizeof
  3. 在循环结束时,记得在循环中 free 所有分配的内存
-- 展开阅读全文 --
头像
PHPnow安装织梦失败怎么办?
« 上一篇 04-04
dede婚庆网站模板如何快速搭建与使用?
下一篇 » 04-04

相关文章

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

目录[+]