You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C语言中检测malloc内存溢出并触发realloc避免未定义行为?

动态分配字符串的安全输入与扩容实现

问题描述

我正在尝试在C语言中处理动态分配的字符串输入,希望当输入字符串超出先前分配的内存时,调用realloc()重新分配内存,而非进入未定义行为。

以下是我的代码:

#include <stdio.h>

int main() {
    char *text, *retext;
    text = malloc(10 * sizeof(*text));
    scanf("%s", text);
    if(text == NULL) {
        printf("\nTry Again: ");
        retext = realloc(text, 20 * sizeof(*retext));
        scanf("%s", retext);
        printf("\n%s", retext);
        free(retext);
        retext = NULL;
    }
    printf("\n%s", text);
    free(text);
    text = NULL;
}

我想要在text的长度(包含\0)超过10时调用realloc()。但我了解到malloc()在内存溢出时不会返回NULL,而是直接进入未定义行为,即便超出10个字符程序看似仍能运行。我希望能够检测到这种即将触发未定义行为的时机,转而执行realloc()相关代码,该如何实现?

原代码的核心问题

你的代码存在两个致命逻辑错误:

  • if(text == NULL)判断的是**malloc内存分配是否失败**,和输入字符串长度是否超限完全无关。只要malloc成功,这个分支永远不会执行,输入溢出时根本不会触发扩容。
  • 使用scanf("%s", text)本身就是不安全的:它会无限制读取输入直到遇到空白字符,完全无视text的内存大小,直接导致缓冲区溢出(未定义行为),此时再检测已经为时已晚。

正确实现思路

要实现安全的动态扩容输入,核心是在输入过程中主动监控已使用的内存,在达到当前分配上限前提前扩容,而非等溢出后处理。推荐两种可靠实现方式:

方式一:逐字符读取(精准控制)

逐个读取输入字符,每存入一个字符就检查当前已使用内存是否接近上限,达到上限时调用realloc扩容,直到遇到终止字符(换行或EOF)。

#include <stdio.h>
#include <stdlib.h>

int main() {
    // 初始分配10字节内存(含字符串结束符\0)
    size_t current_size = 10;
    char *text = malloc(current_size);
    if (text == NULL) {
        fprintf(stderr, "内存分配失败\n");
        return 1;
    }

    size_t length = 0;
    int ch;

    // 逐字符读取输入,直到换行或EOF
    while ((ch = getchar()) != '\n' && ch != EOF) {
        // 检查:当前已存字符数+1(当前字符)+1(\0)是否超过分配内存
        if (length + 2 > current_size) {
            // 扩容策略:每次翻倍,减少realloc调用次数
            current_size *= 2;
            char *temp = realloc(text, current_size);
            if (temp == NULL) {
                fprintf(stderr, "内存扩容失败\n");
                free(text);
                return 1;
            }
            text = temp;
        }
        text[length++] = (char)ch;
    }
    // 添加字符串结束符
    text[length] = '\0';

    // 输出结果
    printf("输入内容:%s\n", text);
    printf("内容长度:%zu\n", length);
    printf("当前分配内存大小:%zu\n", current_size);

    // 释放内存
    free(text);
    text = NULL;

    return 0;
}

关键细节说明

  • 必须检查malloc和realloc的返回值:避免空指针操作,同时防止realloc失败时丢失原内存地址(用临时指针接收返回值)。
  • 扩容判断逻辑:length + 2 > current_size确保预留出存储当前字符和最终\0的空间,不会触发溢出。
  • 翻倍扩容策略:这是行业常用的高效策略,减少内存分配的系统调用次数,提升性能。

方式二:使用fgets结合截断检查

fgets可以指定最大读取长度,我们通过判断输入是否被截断(缓冲区满且无换行符)来触发扩容,然后继续读取剩余内容。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
    size_t current_size = 10;
    char *text = malloc(current_size);
    if (text == NULL) {
        fprintf(stderr, "内存分配失败\n");
        return 1;
    }

    char *newline_pos;
    while (1) {
        // 读取最多current_size-1个字符(留一个位置给\0)
        if (fgets(text, current_size, stdin) == NULL) {
            break; // 读取失败或遇到EOF
        }

        // 检查输入是否完整:查找换行符
        newline_pos = strchr(text, '\n');
        if (newline_pos != NULL) {
            // 去掉换行符,输入完成
            *newline_pos = '\0';
            break;
        } else {
            // 无换行符,说明输入被截断,需要扩容
            current_size *= 2;
            char *temp = realloc(text, current_size);
            if (temp == NULL) {
                fprintf(stderr, "内存扩容失败\n");
                free(text);
                return 1;
            }
            text = temp;
        }
    }

    printf("输入内容:%s\n", text);
    free(text);
    text = NULL;

    return 0;
}

内容的提问来源于stack exchange,提问作者Abdullah Omar Nasseef

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 06:35:51