C语言读取文件最后n行时重复打印最后一行的问题求助
问题:C语言读取文件最后n行时重复打印最后一行
我尝试用C语言读取文件的最后n行并打印,使用fgets()读取行内容的部分似乎正常,但打印存储在数组中的最后n行时,只会重复输出最后一行,应该是存储字符串的方式存在问题。
原代码如下:
#include <stdio.h> #include <stdlib.h> #include <string.h> int main(int agrc, char** agrv) { FILE* input; input = fopen(agrv[1], "r"); int n = *agrv[2]-'0'; int line = 0; char text[11]; char** tab = malloc(1000000*sizeof(text)); while(fgets(text, sizeof(text), input) != 0) { tab[line] = text; line++; } fclose(input); int jump = line-n; for(int i=jump; i<line; i++) { printf("%s", tab[i]); } }
编辑后尝试修改循环,但问题仍然存在:
while(fgets(text, sizeof(text), input) != 0) { char text2[11]; strcpy(text2, text); tab[line] = text2; line++; }
问题原因
原代码的错误:
你把tab[line]指向了栈上的固定数组text,每次调用fgets都会覆盖text里的内容。数组tab中所有元素最终都指向同一个内存地址,打印时自然全是最后一行的内容。编辑后代码的错误:
循环内定义的text2是局部栈变量,每次循环结束后,该变量的内存会被系统回收或复用。tab中存储的都是无效的栈地址,后续访问属于未定义行为,结果依然错误。
修正方案
每次读取一行后,需要为该行内容分配堆内存,保证每行的内容都有独立的存储空间。可以用malloc配合strcpy,或者使用POSIX标准函数strdup(注意部分环境可能需要额外支持)。
修正后的完整代码:
#include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc, char** argv) { // 参数检查 if (argc != 3) { fprintf(stderr, "用法: %s <文件名> <行数n>\n", argv[0]); return 1; } // 打开文件 FILE* input = fopen(argv[1], "r"); if (!input) { perror("打开文件失败"); return 1; } // 转换行数n,支持多位数 int n = atoi(argv[2]); if (n <= 0) { fprintf(stderr, "n必须是正整数\n"); fclose(input); return 1; } int line = 0; char text[11]; // 分配存储指针的数组,每个元素是char*类型 char** tab = malloc(1000000 * sizeof(char*)); if (!tab) { perror("内存分配失败"); fclose(input); return 1; } while (fgets(text, sizeof(text), input) != NULL) { // 为当前行分配内存,长度为字符串长度+1(存终止符) tab[line] = malloc(strlen(text) + 1); if (!tab[line]) { perror("行内存分配失败"); // 释放已分配的内存,避免泄漏 for (int i = 0; i < line; i++) { free(tab[i]); } free(tab); fclose(input); return 1; } // 复制行内容到堆内存 strcpy(tab[line], text); line++; } fclose(input); // 处理文件行数小于n的情况,从第一行开始打印 int jump = line - n; if (jump < 0) jump = 0; // 打印最后n行并释放内存 for (int i = jump; i < line; i++) { printf("%s", tab[i]); free(tab[i]); } free(tab); return 0; }
额外说明
- 原代码中
malloc(1000000*sizeof(text))是错误的,tab是char**类型,每个元素是char*,因此应该用sizeof(char*)计算分配大小。 - 使用
atoi转换行数n比直接*agrv[2]-'0'更健壮,支持两位数及以上的n。 - 增加了参数检查、文件打开检查、内存分配检查,避免程序崩溃。
- 用完内存后及时释放,避免内存泄漏。
- 处理了文件总行数小于n的边界情况,此时会打印所有行。
内容的提问来源于stack exchange,提问作者TCL
相关产品推荐
相关产品推荐

