Linux下C语言读取TXT文件输出异常及Shell命令历史存储问题
两个问题的解决方案:Linux读TXT异常输出 + Shell命令历史存储隐患
一、Linux下C语言读取TXT文件错误输出的排查与解决
你遇到的问题大概率是换行符差异或者编码不兼容导致的,毕竟Windows和Linux的文件系统细节有区别,给你几个实用的解决思路:
1. 处理Windows换行符(\r\n)
Windows生成的TXT文件换行是\r\n,而Linux只识别\n,直接读取会在每行末尾多出一个^M字符(也就是\r)。你可以选两种方式解决:
- 命令行转换:用
dos2unix your_file.txt把文件转成Linux格式; - 代码内过滤:读取时自动去掉
\r,示例代码如下:
#include <stdio.h> #include <string.h> int main() { FILE *fp = fopen("test.txt", "r"); if (!fp) { perror("Failed to open file"); return 1; } char buf[1024]; while (fgets(buf, sizeof(buf), fp)) { // 用strcspn找到第一个\r的位置,替换为字符串结束符 buf[strcspn(buf, "\r")] = '\0'; printf("%s\n", buf); } fclose(fp); return 0; }
2. 解决编码乱码问题
如果你的TXT是Windows下的GBK编码,Linux默认使用UTF-8,中文内容就会乱码。可以:
- 命令行转码:
iconv -f GBK -t UTF-8 input.txt > output.txt; - 代码内处理:用
iconv库在读取时动态转码(编译时需要链接-liconv参数)。
3. 检查文件读取逻辑
确保你没有用错文件打开模式(比如用二进制模式rb读取文本文件,不过Linux下文本与二进制模式差异不大),同时用fgets的返回值判断文件结束,避免while(!feof(fp))这类容易出错的写法。
二、Shell命令历史存储的代码修复
看了你给出的addHistory代码,虽然Windows下能正常运行,但存在几个隐患,在Linux下可能会触发崩溃或逻辑错误,我帮你修正并解释问题点:
原代码的问题
- 满容量时逻辑不完整:
else {...}中没有编写将新命令放到最后一个位置的代码; - 无缓冲区溢出检查:如果输入命令长度超过100字符,
strcpy会直接越界,Linux内存保护严格,会直接导致程序崩溃; - 未过滤空命令:用户输入空行时也会被加入历史,属于无效数据;
- 多余指针赋值:
tempCommand = command完全没必要,直接使用command即可。
修正后的完整代码
#define MAXHIS 20 #define MAX_CMD_LEN 100 // 全局变量必须确保初始化为0! char commandTable[MAXHIS][MAX_CMD_LEN]; int tempHis = 0; void addHistory(char *command) { // 跳过空命令或NULL指针 if (!command || command[0] == '\0') { return; } // 截断过长命令,避免缓冲区溢出 size_t cmd_len = strlen(command); if (cmd_len >= MAX_CMD_LEN) { // 手动添加字符串结束符,防止越界 command[MAX_CMD_LEN - 1] = '\0'; } if (tempHis < MAXHIS) { strcpy(commandTable[tempHis], command); tempHis++; } else { // 将所有历史命令向前移动一位 for (int i = 0; i < MAXHIS - 1; i++) { strcpy(commandTable[i], commandTable[i + 1]); } // 新命令放到最后一个位置 strcpy(commandTable[MAXHIS - 1], command); // tempHis保持MAXHIS不变,无需自增 } }
额外提醒
在Linux下编译时,一定要开启警告选项,能提前发现很多潜在问题:
gcc -Wall -Wextra your_shell.c -o your_shell
比如如果tempHis未初始化,编译器会直接给出警告,避免出现未定义行为。
内容的提问来源于stack exchange,提问作者user9626387
相关产品推荐
相关产品推荐

