C语言读取文件多单词时索引越界致段错误的解决求助
问题分析与修复方案
核心问题点
- 循环条件错误:原代码用
while(fscanf(fp,"%s",word))判断循环,fscanf失败时返回EOF(-1),属于非零值,会导致循环持续执行。当文件单词数不足n时,i会超出words数组的长度,触发越界访问和段错误。 - 索引未做合法性校验:读取到的数字可能超出
words数组的合法索引范围(0到n-1),比如输入n=10时,索引11直接访问会触发段错误。 - 缺少参数与文件校验:未检查命令行参数数量是否正确、n是否为正整数、文件是否成功打开,这些场景都会导致后续操作异常。
- 变长数组潜在风险:使用变长数组存储
indexes和words,如果n过大,会直接导致栈溢出。 - 内存泄漏:
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; }
关键修正说明
- 参数与文件校验:增加了完整的前置校验,避免非法输入导致的程序崩溃。
- 动态内存替代变长数组:用
malloc分配数组,避免大n值导致的栈溢出问题,同时增加了内存分配失败的回滚逻辑。 - 循环条件优化:改为
fscanf(...) == 1 && i < n,确保只在成功读取单词且未达上限时循环,彻底避免越界。 - 索引合法性检查:读取数字后先判断是否在0到n-1范围内,非法索引直接忽略并提示,避免越界访问。
- 内存泄漏修复:所有动态分配的内存都在程序结束前释放,符合C语言内存管理规范。
内容的提问来源于stack exchange,提问作者thatboinick
相关产品推荐
相关产品推荐

