C语言循环管道执行异常求助:大小写转换程序单次正常循环失效
问题分析与修复方案
你的代码存在多个核心逻辑错误,导致循环执行时完全失效,以下是关键问题和修复后的实现:
关键错误点
- 错误使用
feof:while(!feof(in))是典型的错误写法,feof只有在读取到文件末尾后才会置位,会导致最后一行重复处理;且父进程中重新打开input.txt会让读取指针回到开头,触发无限循环。 - 管道与进程重复创建:每次外层循环都创建新管道和进程,且管道写端/读端被过早关闭,后续循环无法继续传输数据。
- 循环终止条件逻辑混乱:子进程中用
strcmp(tst, temp) != 0作为循环终止条件完全不符合实际读取内容,导致逻辑卡死或异常退出。 - 文件指针共享冲突:父子进程共享同一文件指针
in和out,会导致读写位置混乱,数据写入异常。 - 不必要的嵌套fork:你的需求是大小写转换+写入文件,不需要三层进程(父+子+孙),两层进程配合管道即可完成。
修复后的代码
#include <ctype.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> #define BUFF_SIZE 100 int main() { FILE *in, *out; char buff[BUFF_SIZE]; int p1[2]; // 父进程->转换进程的管道 // 打开文件并做错误检查 in = fopen("input.txt", "r"); if (!in) { perror("Failed to open input.txt"); return 1; } out = fopen("output.txt", "w"); if (!out) { perror("Failed to open output.txt"); fclose(in); return 1; } // 仅创建一次管道 if (pipe(p1) == -1) { perror("Pipe creation failed"); fclose(in); fclose(out); return 1; } pid_t convert_pid = fork(); if (convert_pid < 0) { perror("Fork failed"); fclose(in); fclose(out); close(p1[0]); close(p1[1]); return 1; } if (convert_pid > 0) { // 父进程:读取input.txt,写入管道 close(p1[0]); // 关闭读端,父进程只写 // 正确的文件读取循环:用fgets返回值判断 while (fgets(buff, BUFF_SIZE, in) != NULL) { printf("Sending line: %s", buff); // 写入实际有效字节数(包含终止符) write(p1[1], buff, strlen(buff) + 1); } close(p1[1]); // 写完后关闭写端,告知子进程数据传输结束 wait(NULL); // 等待转换进程结束 fclose(in); } else { // 子进程:读取管道数据,转换大小写,写入output.txt close(p1[1]); // 关闭写端,子进程只读 char temp[BUFF_SIZE]; char rev[BUFF_SIZE]; int i; // 读取管道直到EOF(父进程关闭写端后,read返回0) while (read(p1[0], temp, BUFF_SIZE) > 0) { printf("Converting line: %s", temp); // 大小写转换 for (i = 0; temp[i] != '\0'; i++) { rev[i] = isupper(temp[i]) ? tolower(temp[i]) : toupper(temp[i]); } rev[i] = '\0'; // 确保字符串终止 fputs(rev, out); } close(p1[0]); fclose(out); exit(0); } fclose(out); return 0; }
修复说明
- 正确的文件读取逻辑:用
while(fgets(buff, BUFF_SIZE, in) != NULL)替代!feof(in),避免重复读取最后一行。 - 管道与进程仅创建一次:不需要每次循环都新建管道和进程,一次创建即可完成整个文件的处理。
- 管道关闭时机正确:父进程写完所有数据后关闭写端,子进程通过
read返回0判断数据传输结束,替代原来混乱的字符串比较终止条件。 - 简化进程结构:只用两层进程(父进程读文件写管道,子进程读管道转大小写写文件),避免不必要的嵌套fork。
- 完善错误检查:增加文件打开、管道创建、fork的错误检查,方便排查问题。
- 准确的写入长度:写入管道时使用
strlen(buff)+1,确保只传输有效数据,避免多余空字符干扰。
如果你的需求是持续监控input.txt并循环处理(比如文件内容更新后重新处理),可以在外层套一个循环,配合sleep或文件变化检测逻辑,注意每次重新打开文件时重置文件指针,避免重复读取旧内容。
内容的提问来源于stack exchange,提问作者Lauren Hall
相关产品推荐
相关产品推荐

