Linux下C语言管道编程问题:read读取字符串含多余字符
管道传输字符串后出现额外随机字符的问题分析与解决
问题根源
C语言里的字符串依赖'\0'(空字符)作为结束标记,你遇到的问题本质是管道传输时只发送了字符串的有效字符,没包含终止符,而接收端的字符数组是未初始化的局部变量,内存里残留着随机数据。当你用strlen计算长度或者直接打印字符串时,程序会从数组起始位置一直读到内存中第一个'\0',所以就会把后面的随机数据也当成字符串的一部分。
比如你发送的"./test.txt"是10个字符,但接收端的path1数组后面4个字节刚好没有'\0',就会把这4个随机字节也包含进去,导致总长度变成14。
代码里的关键问题点
- 父进程发送时未包含终止符:
你用write(pipe1[1], path, pathLength);只发送了path里的有效字符(strlen(path)的长度),但C字符串的完整结构是有效字符+'\0',这部分终止符没通过管道传过去。 - 接收端数组未初始化:
子进程里的char path1[100], key1[100];是局部数组,默认不会被初始化,数组中未被覆盖的位置会保留栈上的随机垃圾数据。
你的临时解决方法为什么有效
你手动添加path1[pathLength1] = '\0';,相当于在接收的有效字符末尾补上了C字符串必需的终止符,这样strlen和打印时就会在正确的位置停止,不会读取后面的随机数据。这其实是正确的处理方式之一,不是临时方法。
额外的代码优化建议
- 修复fork的运算符优先级问题:
代码里的if(pid = fork() != 0)有坑,!=的优先级比=高,实际执行的是pid = (fork() != 0),导致pid的值是0或1,而不是fork返回的子进程ID。应该改成:if( (pid = fork()) != 0 ) - 检查read/write的返回值:
系统调用read和write可能不会一次性完成所有数据的读写(虽然本地进程间管道通常是原子的,但严谨起见要处理),比如可以循环读取直到拿到指定长度的数据:// 读取pathLength1的示例 ssize_t total_read = 0; while(total_read < sizeof(pathLength1)){ ssize_t ret = read(pipe1[0], (char*)&pathLength1 + total_read, sizeof(pathLength1) - total_read); if(ret < 0){ perror("read error"); exit(1); } total_read += ret; } - 修正文件读取的循环逻辑:
子进程里的while(!feof(f))会导致最后一行被重复处理,因为feof是在读取失败后才会被置位,应该改成用fgets的返回值判断:int i=0; char tmp[500]; while(fgets(tmp, sizeof(tmp), f) != NULL){ i++; if(strstr(tmp, key1) != NULL) printf("Kljucna rec se nalazi u liniji: %d\n", i); } - 确保终止符不会越界:
手动添加'\0'时,要保证pathLength1 < sizeof(path1)-1,避免数组越界。可以在接收前做个判断:if(pathLength1 >= sizeof(path1)){ fprintf(stderr, "Path too long\n"); exit(1); }
另一种可选方案:发送包含终止符的完整字符串
如果不想手动加终止符,也可以在父进程发送时连'\0'一起发送:
write(pipe1[1], path, pathLength + 1); // 多发送一个'\0'
这样子进程读取后直接就能用,不需要手动补终止符,但要注意接收的缓冲区足够大。
内容的提问来源于stack exchange,提问作者Vlada Stefanovic
相关产品推荐
相关产品推荐

