0

I'm trying to pipe a file to my program using type file.txt | myprogram.exe. I'm reading it in with:

char *line;
struct block *newblock, *cur;
int i, osl, cbs, rs;
int startblock;

/* read in the blocks ... */
while (!feof(stdin) && !ferror(stdin)) {
    cbs = 2048;
    line = (char *)malloc(cbs + 1);
    if (!line) {
        perror("malloc");
        exit(1);
    }
    line[cbs] = '\0';

    /* read in the line */
    if (!fgets(line, cbs, stdin)) {
        free(line);
        continue;
    } else {
        while (line[cbs - 2]) {
            /* expand the line */
            line = (char *)realloc(line, (cbs * 2) + 1);
            if (!line) {
                perror("realloc");
                exit(1);
            }
            line[cbs * 2] = '\0';

            /* read more */
            if (!fgets(line + cbs - 1, cbs + 1, stdin))
                break;

            cbs *= 2;
        }
    }
    ...
}

But just after reading the first line, feof() returns true, even though there are multiple lines in the file. How can that happen?

chqrlie
  • 131,814
  • 10
  • 121
  • 189
  • 1
    Please take some time to read [Why is “while (!feof(file))” always wrong?](https://stackoverflow.com/questions/5431941/why-is-while-feoffile-always-wrong) – Some programmer dude Jul 08 '19 at 18:41
  • Looks like `while (line[cbs - 2])` can read the whole file in the inner loop, as it is checking what can be uninitialised memory. – Weather Vane Jul 08 '19 at 18:44
  • As for your algorithm it seems totally wrong. If you want to read a line without knowing its exact length, then use `fgets` (like you're doing) but check if the string ends with a newline or not. If there's no newline at the end then there's more of the line to read. Use `strchr` or `strcspn` to find out if there's a newline at the end (of the string, which might not be the end of the array!). – Some programmer dude Jul 08 '19 at 18:45

1 Answers1

1

The code has multiple problems:

  • the test for end of file is incorrect: feof() only provides meaningful information after a read function has failed.
  • the reallocation scheme is broken: you test the second to last byte of the array, but fgets() may not have set this byte if the line is shorter.

Here is how you can fix your program:

  • either use getline() if your system supports it. getline() allocates a large enough buffer to read a full line at a time.
  • or use fgets to read a line fragment and check if it ends with a newline.
chqrlie
  • 131,814
  • 10
  • 121
  • 189