c语言malloc realloc

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

目录

  1. 为什么需要动态内存分配?
  2. malloc (Memory Allocate) - 分配内存
    • 函数原型
    • 功能
    • 使用示例
    • 关键点与注意事项
  3. realloc (Reallocate) - 重新分配内存
    • 函数原型
    • 功能
    • 使用示例
    • 关键点与注意事项
  4. mallocrealloc 的核心区别
  5. 完整的最佳实践示例

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

在 C 语言中,内存主要分为几个区域:

c语言malloc realloc
(图片来源网络,侵删)
  • 栈区:存储局部变量、函数参数等,编译器自动管理,速度快,但大小有限,当函数结束时,栈上的内存会自动释放。
  • 静态/全局区:存储全局变量和静态变量,程序运行期间一直存在。
  • 常量区:存储字符串字面量等常量。
  • 堆区:这是动态内存分配的区域,程序员手动申请和释放,堆的大小通常比栈大得多,生命周期由程序员控制,直到 free() 被调用。

什么时候需要堆内存?

  1. 编译时大小未知:你需要存储用户输入的字符串,但不知道用户会输入多长。
  2. 数据量非常大:如果数据量超过了栈的容量(通常是几 MB),就必须放在堆上。
  3. 需要长期存在:函数返回后,栈上的局部变量会销毁,如果希望数据在函数调用之间仍然有效,必须将其放在堆上。

malloc (Memory Allocate) - 分配内存

malloc 的作用是在堆区申请一块指定大小的连续内存空间。

函数原型

#include <stdlib.h> // 或 <malloc.h>
void *malloc(size_t size);
  • 参数size_t size - 你希望分配的内存字节数。
  • 返回值
    • 成功时:返回一个指向分配好的内存块起始地址void* 指针。
    • 失败时:返回 NULL 指针(因为堆内存可能已耗尽)。

功能

  1. 向操作系统请求 size 字节的内存。
  2. 如果请求成功,返回一个指向该内存的通用指针 (void*)。
  3. 重要malloc 不会初始化这块内存,内存中的值是随机的“垃圾值”。

使用示例

#include <stdio.h>
#include <stdlib.h>
int main() {
    int n = 5;
    int *ptr;
    // 1. 分配足够的内存来存储 5 个 int
    // sizeof(int) * 5 得到所需的总字节数
    ptr = (int *)malloc(n * sizeof(int));
    // 2. 检查分配是否成功
    if (ptr == NULL) {
        printf("内存分配失败!\n");
        return 1; // 返回错误码
    }
    printf("成功分配了 %d 个 int 的内存,\n", n);
    // 3. 使用这块内存 (像普通数组一样)
    for (int i = 0; i < n; i++) {
        ptr[i] = i * 10; // 初始化
        printf("ptr[%d] = %d\n", i, ptr[i]);
    }
    // 4. 释放内存 (非常重要!)
    free(ptr);
    ptr = NULL; // 好习惯:将指针置为NULL,防止悬垂指针
    return 0;
}

关键点与注意事项

  1. 包含头文件:必须包含 <stdlib.h>
  2. 检查返回值malloc 可能会失败,永远不要假设它一定成功,必须检查返回的指针是否为 NULL
  3. 类型转换malloc 返回 void*,通常需要将其转换为你需要的指针类型(如 int*, char*),虽然现代 C 编译器(如 C99 之后)允许你直接赋值,但显式转换是更传统和清晰的做法。
  4. 计算大小:最好使用 sizeof(数据类型) * 数量 的方式来计算所需字节数,而不是直接写一个数字,这样更具可移植性。
  5. 未初始化malloc 分配的内存是“脏”的,必须在使用前手动初始化。
  6. 必须释放:使用完毕后,必须调用 free() 将内存归还给系统,否则会导致内存泄漏

realloc (Reallocate) - 重新分配内存

当你发现之前分配的内存空间不够用,或者想缩减它的大小时,就可以使用 realloc

函数原型

#include <stdlib.h>
void *realloc(void *ptr, size_t new_size);
  • 参数
    • void *ptr:指向之前由 malloc, calloc, 或 realloc 分配的内存块的指针。
    • size_t new_size:你希望调整到的新的大小(字节数)。
  • 返回值
    • 成功时:返回一个指向内存块的起始地址的指针。
    • 失败时:返回 NULL 指针,并且原来的内存块保持不变

功能

realloc 是一个非常强大的函数,它处理以下几种情况:

c语言malloc realloc
(图片来源网络,侵删)
  1. 在原地扩展ptr 指向的内存块后面有足够的空闲空间,realloc 会直接在原地扩展这块内存,并返回原来的地址
  2. 需要移动数据:如果后面的空间不够,realloc 会在堆上找一个足够大的新位置,分配一块 new_size 大小的内存,然后将旧内存块中的所有数据复制到新位置,然后释放旧内存块,并返回新地址
  3. 缩小内存new_size 可以比原来的小,realloc 会缩小内存块,并返回原来的地址。
  4. 释放内存new_size 为 0,realloc 的行为等同于 free(ptr),并返回 NULL
  5. 处理 NULL 指针ptrNULLrealloc(new_size) 的行为等同于 malloc(new_size)

使用示例

#include <stdio.h>
#include <stdlib.h>
int main() {
    int *numbers = (int *)malloc(3 * sizeof(int));
    if (numbers == NULL) {
        printf("初始内存分配失败!\n");
        return 1;
    }
    // 初始化并打印初始数据
    for (int i = 0; i < 3; i++) {
        numbers[i] = i + 1;
        printf("numbers[%d] = %d\n", i, numbers[i]);
    }
    // 假设现在需要存储 5 个数字,而不是 3 个
    printf("\n需要扩展内存...\n");
    // 使用 realloc 扩展内存
    int *temp = (int *)realloc(numbers, 5 * sizeof(int));
    // 检查 realloc 是否成功
    if (temp == NULL) {
        printf("内存重新分配失败!\n");
        free(numbers); // 即使失败,也要释放原来的内存
        return 1;
    }
    // realloc 成功,它会返回一个新地址
    // 必须更新你的指针变量,否则会丢失新内存的地址
    numbers = temp;
    // 新内存的旧部分数据是保留的,新部分是未初始化的
    for (int i = 3; i < 5; i++) {
        numbers[i] = i + 1; // 初始化新元素
    }
    printf("\n扩展后的数据:\n");
    for (int i = 0; i < 5; i++) {
        printf("numbers[%d] = %d\n", i, numbers[i]);
    }
    // 释放最终分配的内存
    free(numbers);
    numbers = NULL;
    return 0;
}

关键点与注意事项

  1. 检查返回值realloc 也可能失败。最经典的错误是直接 ptr = realloc(ptr, new_size);realloc 失败并返回 NULLptr 就会被赋值为 NULL,你就丢失了原来内存块的地址,导致无法释放,造成内存泄漏。
  2. 使用临时指针:正确的做法是先用一个临时指针接收 realloc 的返回值,检查成功后再更新原指针。
    int *new_ptr = realloc(old_ptr, new_size);
    if (new_ptr != NULL) {
        old_ptr = new_ptr;
    } else {
        // 处理错误,但 old_ptr 仍然有效
        printf("realloc 失败,但 old_ptr 仍然可用,\n");
    }
  3. 数据安全realloc 保证旧数据会被完整地复制到新内存中(除非 new_size 比原来小)。
  4. 内存释放realloc 成功,它会自动释放旧的内存块,你只需要在最后 free() 新的内存块即可。

mallocrealloc 的核心区别

特性 malloc realloc
目的 初次分配一块内存。 调整**已存在**内存块的大小。
参数 一个参数:要分配的字节数 (size)。 两个参数:旧内存地址 (ptr),新的大小 (new_size)。
对旧内存的处理 不涉及旧内存。 保留旧内存中的数据(除非缩小),如果移动,会自动释放旧内存。
对NULL指针的处理 malloc(NULL) 是错误的用法。 realloc(NULL, size) 的行为等同于 malloc(size)

完整的最佳实践示例

这个示例展示了如何创建一个可以动态增长的“数组”。

#include <stdio.h>
#include <stdlib.h>
int main() {
    int capacity = 2; // 初始容量
    int size = 0;     // 当前元素个数
    int *dynamic_array = (int *)malloc(capacity * sizeof(int));
    if (dynamic_array == NULL) {
        fprintf(stderr, "内存分配失败!\n");
        return 1;
    }
    printf("请输入一系列整数,以 0 \n");
    int input;
    while (1) {
        scanf("%d", &input);
        if (input == 0) {
            break; // 输入0结束
        }
        // 检查是否需要扩容
        if (size == capacity) {
            printf("数组已满,容量从 %d 扩展到 %d\n", capacity, capacity * 2);
            capacity *= 2; // 容量翻倍
            int *temp = (int *)realloc(dynamic_array, capacity * sizeof(int));
            if (temp == NULL) {
                fprintf(stderr, "内存重新分配失败! 已输入数据:\n");
                // realloc失败,dynamic_array仍然指向原来的有效内存
                break;
            }
            dynamic_array = temp; // 更新指针
        }
        dynamic_array[size] = input;
        size++;
    }
    printf("\n您输入的数字是:\n");
    for (int i = 0; i < size; i++) {
        printf("%d ", dynamic_array[i]);
    }
    printf("\n");
    // 释放内存
    free(dynamic_array);
    dynamic_array = NULL;
    return 0;
}

  • malloc 是你的“开荒工具”,用于在堆上申请一块全新的、未初始化的土地。
  • realloc 是你的“扩建工具”,用于调整已有土地的大小,它非常智能,可以原地扩建,也可以在别处找块新地并帮你搬家。
  • 黄金法则
    1. 总是检查 mallocrealloc 的返回值是否为 NULL
    2. malloc/calloc 分配的内存,最终必须用 free 释放。
    3. realloc 可能返回新地址,务必用临时变量接收并检查后再更新你的指针。

掌握了这两个函数,你就掌握了 C 语言动态内存分配的核心,能够编写出更灵活、更强大的程序。

-- 展开阅读全文 --
头像
dede大气企业网站模板(一屏展示)
« 上一篇 前天
织梦ckplayer插件如何实现视频播放与适配?
下一篇 » 前天

相关文章

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

目录[+]