stdio过滤器在管道传输时崩溃了。

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 会抱怨。我不确定 strfryNULL 输入时的行为。我认为将 fgetsstrfry 调用分开并检查 NULL 更加清晰。 - M Oehm
1
顺便说一句:在我看来,fopen 失败后悄无声息地回退到 stdin 并不是一个好的设计。 - M Oehm
@M Oehm:它是一个stdio过滤器,就像rev一样,因此回退到stdin是合理的。 - Erkin Alp Güney
1
也许吧。在这段时间里,你对原始代码做了那么多修改,你还能观察到相同的行为吗? - M Oehm
观察得很好。将 fgets(buf,4095,stdin) 更改为 fgets(buf,4095,fryend) 应该会有所不同.... - wimh
3个回答

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

来自 fgets() 的 man 手册

返回值

[...] fgets() 在错误或读取字符前遇到文件结束时返回 NULL。

然后将 NULL 传递给 strfry()

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

这不是一个好主意。


0

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

因此,您的循环应该像这样:

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

我已经删除了memset,因为fgets的结果是以null结尾的,并且不会溢出缓冲区,所以您可以传递完整的4096字节长度。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接