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

运行时为字符串分配内存:统计'2'后接'1'出现次数的程序问题

修复动态字符串分配与"21"统计逻辑的问题

看起来你在实现一个统计字符串中"21"出现次数的程序,不过原代码的动态字符串分配逻辑和一些细节存在问题,我来帮你梳理并修复这些问题:

原代码的核心问题

  • 未重置的索引变量:main函数里的i定义在测试用例循环外,每次处理新测试用例时不会重置为0,会导致后续字符串写入内存越界。
  • 动态内存分配的错误:
    1. 初始malloc(1*sizeof(char))仅分配1字节,写入第一个字符后就需要扩容,但realloc逻辑不完整,也没有检查分配是否成功。
    2. 未处理realloc失败的情况(返回NULL),可能导致程序崩溃。
  • 输入缓冲区残留问题:scanf("%d", &t)读取测试用例数量后,输入缓冲区会留下换行符,第一个getc(stdin)会读取到这个换行符,导致第一个测试用例的字符串为空或错误。
  • 越界访问风险:penalty_shoot函数中,当遍历到字符串最后一个字符时,s[i+1]会访问超出'\0'的内存,属于未定义行为。
  • 内存泄漏:每个测试用例分配的字符串用完后未调用free,会导致内存泄漏。

修复后的完整代码

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

int penalty_shoot(char* s) {
    int count = 0;
    // 遍历到倒数第二个字符即可,避免访问s[i+1]越界
    for (int i = 0; s[i] != '\0' && s[i+1] != '\0'; i++) {
        if (s[i] == '2' && s[i+1] == '1') {
            count++;
        }
    }
    return count;
}

int main() {
    int t;
    // 读取测试用例数量后,清除输入缓冲区的换行符
    if (scanf("%d", &t) != 1) {
        fprintf(stderr, "Failed to read test case count\n");
        return 1;
    }
    // 清除scanf留下的换行符
    while (getchar() != '\n');

    while (t--) {
        char *str = NULL;
        size_t len = 0;
        int c;

        // 使用getline简化动态字符串读取(POSIX标准,Windows环境可替换为自定义逻辑)
        if (getline(&str, &len, stdin) == -1) {
            fprintf(stderr, "Failed to read string\n");
            free(str);
            continue;
        }

        // 去掉getline读取到的换行符(如果存在)
        size_t str_len = strlen(str);
        if (str_len > 0 && str[str_len - 1] == '\n') {
            str[str_len - 1] = '\0';
        }

        int result = penalty_shoot(str);
        printf("Count: %d\n", result);

        // 释放动态分配的内存,避免泄漏
        free(str);
    }
    return 0;
}

关键修复点解释

  1. 优化统计函数:

    • 把遍历条件改为s[i] != '\0' && s[i+1] != '\0',确保不会访问超出字符串范围的内存,规避未定义行为。
    • 合并两个if为一个逻辑判断,代码更简洁易读。
  2. 修复输入处理:

    • 在scanf后添加while (getchar() != '\n');,清除输入缓冲区里残留的换行符,避免第一个测试用例读取到空字符串。
    • 使用getline函数(POSIX标准)自动处理动态字符串的分配和扩容,简化代码逻辑。如果你的环境不支持getline,可以用下面的手动实现版本替代。
  3. 内存管理优化:

    • 每个测试用例结束后调用free(str),释放动态分配的内存,避免内存泄漏。
    • 检查getline的返回值,处理读取失败的情况。

手动实现动态字符串读取(替代getline)

如果你的编译器不支持getline,可以用下面的手动扩容逻辑替换:

char *str = malloc(1 * sizeof(char));
if (str == NULL) {
    fprintf(stderr, "Memory allocation failed\n");
    continue;
}
size_t current_size = 1;
size_t index = 0;
int c;

// 读取字符,直到换行或EOF
while ((c = getchar()) != '\n' && c != EOF) {
    // 检查是否需要扩容
    if (index >= current_size - 1) { // 留一个位置给'\0'
        current_size *= 2;
        char *temp = realloc(str, current_size * sizeof(char));
        if (temp == NULL) {
            fprintf(stderr, "Reallocation failed\n");
            free(str);
            str = NULL;
            break;
        }
        str = temp;
    }
    str[index++] = (char)c;
}

if (str != NULL) {
    str[index] = '\0'; // 添加字符串结束符
    int result = penalty_shoot(str);
    printf("Count: %d\n", result);
    free(str);
}

这个手动版本中,每次内存不足时会扩容为原来的2倍,同时检查malloc和realloc的返回值确保分配成功,最后手动添加字符串结束符'\0'。

内容的提问来源于stack exchange,提问作者yogi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 08:50:18