5

I am trying to write a cat clone to exercise C, I have this code:

#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;
}

I tried echo "1..2..3.." | ./cat and ./cat < garbage.txt but I don't see any output on terminal. What I am doing wrong here?

Edit: According to comments and answers, I ended up doing this:

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;
    }

}
yasar
  • 13,158
  • 28
  • 95
  • 160
  • 4
    Don't use `feof` as your loop condition; it won't return true until *after* you've attempted to read past the end of the file, so your loop may execute once too often. Check the result of `fread` instead, and if it's smaller than BLOCK_SIZE, *then* call `feof` to check for end-of-file. And you need to add `fflush(stdout);` after the `fwrite` call. – John Bode Apr 12 '12 at 18:14
  • 1
    here fread() nearly always results zero bytes unless you typed in exactly 512 chars. – Peter Miehle Apr 12 '12 at 18:17
  • 1
    @JohnBode How does my edit look? – yasar Apr 12 '12 at 18:32
  • 2
    Better, although you probably want to check the number of bytes returned *before* writing to `stdout`. You could reverse the sense of the test, like `if (bytes > 0) fwrite(...) else break;`; after all, if you get 0 bytes back, you might as well have hit EOF. – John Bode Apr 12 '12 at 18:43

4 Answers4

8

i can quote an answer by me: https://stackoverflow.com/a/296018/27800

fread(buffer, sizeof(char), block_size, stdin);
Community
  • 1
  • 1
Peter Miehle
  • 5,984
  • 2
  • 38
  • 55
2

Your problem appears to be the return value of fread. I modified your code to print out the value bytes, and I get 0 every time. The man page for fread makes it clear that the return value of fread is NOT the number of characters. If EOF is encountered the return value could be zero (which it is in this case). This is because you are attempting to read in 1 thing that is size BLOCK_SIZE rather than BLOCK_SIZE things that are size 1.

natet
  • 96
  • 3
  • the result of fread() is the number of bytes read, but parameter 2 and 3 do specify the behaviour: "1 block of size n", versus "up to n blocks of size 1". In the OPs code, he wants one block of size 512. – Peter Miehle Apr 12 '12 at 18:28
  • Yeah, I read your answer just as I was posting mine. I just added an edit to make that more clear. Your answer on the other post may be a little hard to parse for someone new to the language. I also voted for your answer :) – natet Apr 12 '12 at 18:31
1

Try calling fflush(stdout) after the fwrite()

1

Ignore my comment about fflush; that's not the issue.

Swap the order of the block size and the element size in the fread call. You want to read up to BLOCK_SIZE elements of size 1 (sizeof (char) is 1 by definition); what you're doing is trying to read 1 element of size BLOCK_SIZE, so unless you type in at least BLOCK_SIZE characters, fread will return 0. IOW, your fread call needs to be

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

Make a similar change to the fwrite call.

John Bode
  • 119,563
  • 19
  • 122
  • 198