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

C语言读取文件多单词时索引越界致段错误的解决求助

问题分析与修复方案

核心问题点

  1. 循环条件错误:原代码用while(fscanf(fp,"%s",word))判断循环,fscanf失败时返回EOF(-1),属于非零值,会导致循环持续执行。当文件单词数不足n时,i会超出words数组的长度,触发越界访问和段错误。
  2. 索引未做合法性校验:读取到的数字可能超出words数组的合法索引范围(0到n-1),比如输入n=10时,索引11直接访问会触发段错误。
  3. 缺少参数与文件校验:未检查命令行参数数量是否正确、n是否为正整数、文件是否成功打开,这些场景都会导致后续操作异常。
  4. 变长数组潜在风险:使用变长数组存储indexes和words,如果n过大,会直接导致栈溢出。
  5. 内存泄漏:malloc分配的words元素未释放,会造成内存泄漏。

修正后的代码

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

int main(int argc, char const *argv[])
{
    // 校验命令行参数数量
    if (argc != 3) {
        fprintf(stderr, "用法: %s <n> <文件名>\n", argv[0]);
        return EXIT_FAILURE;
    }

    int n = atoi(argv[1]);
    // 校验n是否为正整数
    if (n <= 0) {
        fprintf(stderr, "n必须是正整数\n");
        return EXIT_FAILURE;
    }

    // 动态分配数组,避免栈溢出
    int *indexes = malloc(n * sizeof(int));
    char **words = malloc(n * sizeof(char *));
    if (!indexes || !words) {
        fprintf(stderr, "内存分配失败\n");
        free(indexes);
        free(words);
        return EXIT_FAILURE;
    }

    // 为每个单词分配内存
    for (int i = 0; i < n; i++) {
        words[i] = malloc(256 * sizeof(char));
        if (!words[i]) {
            fprintf(stderr, "内存分配失败\n");
            // 释放已分配的内存,避免泄漏
            for (int j = 0; j < i; j++) {
                free(words[j]);
            }
            free(words);
            free(indexes);
            return EXIT_FAILURE;
        }
        indexes[i] = -1;
    }

    // 打开文件并校验
    FILE *fp = fopen(argv[2], "r");
    if (!fp) {
        fprintf(stderr, "无法打开文件 %s\n", argv[2]);
        // 清理内存
        for (int i = 0; i < n; i++) {
            free(words[i]);
        }
        free(words);
        free(indexes);
        return EXIT_FAILURE;
    }

    char word[256];
    int i = 0, j = 0;
    // 正确判断读取状态,同时限制读取数量不超过n
    while (fscanf(fp, "%s", word) == 1 && i < n) {
        strcpy(words[i], word);
        // 判断是否为数字(支持负数字,不需要可移除负号判断)
        if (isdigit(word[0]) || (word[0] == '-' && isdigit(word[1]))) {
            int idx = atoi(word);
            // 校验索引是否在合法范围内
            if (idx >= 0 && idx < n) {
                indexes[j++] = idx;
            } else {
                fprintf(stderr, "警告:索引 %d 超出范围,已忽略\n", idx);
            }
        }
        i++;
    }
    fclose(fp);

    // 输出结果
    for (i = 0; i < j; i++) {
        printf("%s ", words[indexes[i]]);
    }
    printf("\n");

    // 释放所有动态分配的内存
    for (int k = 0; k < n; k++) {
        free(words[k]);
    }
    free(words);
    free(indexes);

    return EXIT_SUCCESS;
}

关键修正说明

  1. 参数与文件校验:增加了完整的前置校验,避免非法输入导致的程序崩溃。
  2. 动态内存替代变长数组:用malloc分配数组,避免大n值导致的栈溢出问题,同时增加了内存分配失败的回滚逻辑。
  3. 循环条件优化:改为fscanf(...) == 1 && i < n,确保只在成功读取单词且未达上限时循环,彻底避免越界。
  4. 索引合法性检查:读取数字后先判断是否在0到n-1范围内,非法索引直接忽略并提示,避免越界访问。
  5. 内存泄漏修复:所有动态分配的内存都在程序结束前释放,符合C语言内存管理规范。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 23:50:37