corporateWhore corporateWhore - 2 months ago 8
C Question

Reading text file from stdin stops at last line

I wrote a short program to test reading text files from

stdin
:

int main(){
char c;

while(!feof(stdin)){

c = getchar(); //on last iteration, this returns '\n'

if(!isspace(c)) //so this is false
putchar(c);

//remove spaces
while (!feof(stdin) && isspace(c)){ //and this is true
c = getchar(); // <-- stops here after last \n
if(!isspace(c)){
ungetc(c, stdin);
putchar('\n');
}
}
}
return 0;
}


I then pass it a small text file:

jimmy 8
phil 6
joey 7


with the last line (
joey 7
) terminated with a
\n
character.

My problem is, after it reads and prints the last line, then loops back to check for more input, there are no more characters to read and it just stops at the line noted in the code block.

Question: The only way for
feof()
to return true is after a failed read as noted here: Detecting EOF in C. Why isn't the final call to
getchar
triggering EOF and how can I better handle this event?

Answer

There are multiple problems in your code:

  • You do not include <stdio.h>, nor <ctype.h>, or at least you did not post the whole source code.
  • You use feof() to check for end of file. This is almost never the right method, as underscored in Why is “while ( !feof (file) )” always wrong?
  • You read the byte from the stream in a char variable. This prevents proper testing for EOF and also causes undefined behavior for isspace(c). Change the type to int.

Here is an improved version:

#include <stdio.h>

int main(void) {
    int c;

    while ((c = getchar()) != EOF) {
        if (!isspace(c)) {
            putchar(c);
        } else {
            //remove spaces
            while ((c = getchar()) != EOF && isspace(c)) {
                continue;  // just ignore extra spaces
            }
            putchar('\n');
            if (c == EOF)
                break;
            ungetc(c, stdin);
        }
    }
    return 0;
}

While your method with ungetc() is functionally correct, it would be better to use an auxiliary variable this way:

#include <stdio.h>
#include <ctype.h>

int main(void) {
    int c, last;

    for (last = '\n'; ((c = getchar()) != EOF; last = c) {
        if (!isspace(c)) {
            putchar(c);
        } else
        if (!isspace(last))
            putchar('\n');
        }
    }
    return 0;
}
Comments