2014-12-07 73 views
3

我已经使用strfry编写了一个字符串字符串程序。它的默认标准输入工作很大,但与标准输入输出重定向使用时崩溃(功能,但内存设计缺陷末):stdio过滤器在管道中崩溃

#include "stdio.h" 
#include "stdlib.h" 
#include "string.h" 
#include "sys/mman.h" 

int main(int argc,char *argv[]) { 
    FILE *fryend=stdin; 
    if (argc==1) goto mainloop; 
    if (argc>1) fryend=fopen(argv[1],"r") ? fryend : stdin; 

    mainloop:; 
    char *buf=malloc(4096); 
    while (!ferror(fryend)) { 
     memset(buf,0,4096); 
     strfry(fgets(buf,4095,fryend)); 
     fputs(buf,stdout); 
    } 
    free(buf); 
    if (fryend!=stdin) fclose(fryend); 
    return 0; 
} 

这里有什么问题?使用GNU libc/GCC。通过valgrind运行,没有检测到内存泄漏。

+2

你的'fgets'调用总是在'stdin'上工作。如果'fryend'是一个文件,你应该'fclose',否则Valgrind会抱怨。我不确定''strfry'在NULL输入上的行为如何。我认为分离'fgets'和'strfry'调用并检查'NULL'是更清晰的。 – 2014-12-07 09:18:12

+1

作为一个方面说明:在我看来,让一个失败的fopen无声地回落到stdin并不是一个好设计。 – 2014-12-07 09:19:33

+0

@M Oehm:这是一个stdio过滤器,就像'rev'一样,所以回退到'stdin'是合理的。 – 2014-12-07 09:37:52

回答

0

fgets返回NULL到达文件末尾时。您应该使用此返回值而不是调用ferrorfeof来控制您的循环。您还应该小心,不要将NULL指针传递给字符串函数。他们可能会优雅地处理,但通常不会。

所以,你的循环应该是这样的:

while (fgets(buf, 4096, fryend)) { 
    strfry(buf); 
    fputs(buf, stdout); 
} 

我已经抛出了memset,因为fgets结果是空值终止,不会溢出缓冲区,这样你就可以通过完整的4096字节长度。

1

改写这一行

if (argc>1) fryend=fopen(argv[1],"r") ? fryend : stdin; 

没有条件运算符。

也许像

if (argc > 1) { 
    FILE *tmp = fopen(argv[1], "r"); 
    if (tmp) fryend = tmp; 
} 
0

当重定向stdin

a.out <test.txt 

fgets()可能返回NULL

man fgets()来自:

返回值

[...]与fgets()的返回[S] [...]上错误NULL或当文件的端发生,而没有字符已被阅读。

反过来NULL被传递给strfry()

strfry(fgets(buf, 4095, fryend)); 

这是不是一个好主意。