使用C语言从标准输入读取并写入标准输出

5

我正在尝试编写一个猫克隆程序来练习C语言,我有这段代码:

#include <stdio.h>
#define BLOCK_SIZE 512
int main(int argc, const char *argv[])
{
    if (argc == 1) { // copy stdin to stdout
        char buffer[BLOCK_SIZE];
        while(!feof(stdin)) {
            size_t bytes = fread(buffer, BLOCK_SIZE, sizeof(char),stdin);
            fwrite(buffer, bytes, sizeof(char),stdout);
        }
    }
    else printf("Not implemented.\n");
    return 0;
}

我尝试了echo "1..2..3.." | ./cat./cat < garbage.txt,但是在终端上没有看到任何输出。我做错了什么?

编辑: 根据评论和答案,最终我做了如下操作:

void copy_stdin2stdout()
{
    char buffer[BLOCK_SIZE];
    for(;;) {
        size_t bytes = fread(buffer,  sizeof(char),BLOCK_SIZE,stdin);
        fwrite(buffer, sizeof(char), bytes, stdout);
        fflush(stdout);
        if (bytes < BLOCK_SIZE)
            if (feof(stdin))
                break;
    }

}

4
不要使用 feof 作为循环条件;它只有在尝试读取文件末尾后才会返回 true,因此您的循环可能会执行多一次。相反,应该检查 fread 的结果,如果小于 BLOCK_SIZE,则调用 feof 检查文件是否已结束。在 fwrite 调用之后需要添加 fflush(stdout); - John Bode
1
这里的fread()函数几乎总是返回零字节,除非您输入了恰好512个字符。 - Peter Miehle
1
@JohnBode,我的修改看起来怎么样? - yasar
2
更好的做法是在写入stdout之前检查返回的字节数。你可以反转测试的意义,例如 if (bytes > 0) fwrite(...) else break;;毕竟,如果你收到了0字节,那么你可能已经到达了EOF。 - John Bode
4个回答

8

2
你的问题似乎出在fread的返回值上,我修改了你的代码以打印出字节数量,每次都得到0。fread的手册清楚地指出,fread的返回值不是字符数。如果遇到EOF,返回值可能为零(在这种情况下确实是零)。这是因为你正在尝试读取一个大小为BLOCK_SIZE的东西,而不是BLOCK_SIZE个大小为1的东西。

fread() 的结果是读取的字节数,但第二个和第三个参数确实指定了行为:“大小为 n 的一个块”和“大小为 1 的最多 n 个块”。在 OP 的代码中,他想要一个大小为 512 的块。 - Peter Miehle
是的,我在发布我的回答时刚好看到了你的回答。我只是添加了一个编辑来使它更清晰明了。对于刚接触这门语言的人来说,你在另一篇帖子中的回答可能有点难以理解。我也投票支持了你的回答 :) - natet

1
尝试在fwrite()之后调用fflush(stdout)

1

忽略我的关于 fflush 的评论;那不是问题所在。

fread 调用中交换块大小和元素大小的顺序。你想要读取最多 BLOCK_SIZE 个大小为 1 的元素(根据定义,sizeof(char) 的大小为 1);而你现在正在尝试读取大小为 BLOCK_SIZE 的 1 个元素,因此除非输入至少 BLOCK_SIZE 个字符,fread 将返回 0。也就是说,你的 fread 调用需要如下:

size_t bytes = fread(buffer, 1, sizeof buffer, stdin);

fwrite 调用进行类似的更改。


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