End of File in C++

End of File (EOF) in C

EOF indicates "end of file". A newline (which is what happens when you press enter) isn't the end of a file, it's the end of a line, so a newline doesn't terminate this loop.

The code isn't wrong[*], it just doesn't do what you seem to expect. It reads to the end of the input, but you seem to want to read only to the end of a line.

The value of EOF is -1 because it has to be different from any return value from getchar that is an actual character. So getchar returns any character value as an unsigned char, converted to int, which will therefore be non-negative.

If you're typing at the terminal and you want to provoke an end-of-file, use CTRL-D (unix-style systems) or CTRL-Z (Windows). Then after all the input has been read, getchar() will return EOF, and hence getchar() != EOF will be false, and the loop will terminate.

[*] well, it has undefined behavior if the input is more than LONG_MAX characters due to integer overflow, but we can probably forgive that in a simple example.

What is EOF in the C programming language?

On Linux systems and OS X, the character to input to cause an EOF is Ctrl-D. For Windows, it's Ctrl-Z.

Depending on the operating system, this character will only work if it's the first character on a line, i.e. the first character after an Enter. Since console input is often line-oriented, the system may also not recognize the EOF character until after you've followed it up with an Enter.

And yes, if that character is recognized as an EOF, then your program will never see the actual character. Instead, a C program will get a -1 from getchar().

Representing EOF in C code?

EOF is not a character (in most modern operating systems). It is simply a condition that applies to a file stream when the end of the stream is reached. The confusion arises because a user may signal EOF for console input by typing a special character (e.g Control-D in Unix, Linux, et al), but this character is not seen by the running program, it is caught by the operating system which in turn signals EOF to the process.

Note: in some very old operating systems EOF was a character, e.g. Control-Z in CP/M, but this was a crude hack to avoid the overhead of maintaining actual file lengths in file system directories.

End of File (EOF) in C program

The program does not function as expected for 2 reasons:

  • bytes read from stdin are not numeric values: if the user type 1, the program receives '1' which is the character value, not the numeric value. You can compute the numeric value of a digit character by subtracting the character value of '0':

    int c = getchar();
    if (c >= '0' && c <= '9') {
    int grade = c - '0';
    /* you can now test the grade */
  • You read standard input one byte at a time: it does not allow for grades that exceed 9. If the user types 10, you will be testing 2 grades and output Failed! twice.

Here is a alternate version with scanf():

#include <stdio.h>

int main(void) {
int grade;
puts("Enter the grades\n");
puts("Enter the EOF character to end input\n");

while (scanf("%d", &grade) == 1) {
if (grade >= 8) {
puts("Passed with High Pass");
} else
if (grade >= 5) {
puts("Passed");
} else {
puts("Failed\n");
}
}
return 0;
}

Detecting EOF in C

EOF is just a macro with a value (usually -1). You have to test something against EOF, such as the result of a getchar() call.

One way to test for the end of a stream is with the feof function.

if (feof(stdin))

Note, that the 'end of stream' state will only be set after a failed read.

In your example you should probably check the return value of scanf and if this indicates that no fields were read, then check for end-of-file.

Solve ÿ end of file in C

For each character you read, you have two things to do:

  1. Check to see if it's EOF.
  2. If not, write it to the output.

Your problem is you're doing these two things in the wrong order.

There are potentially several different ways of solving this. Which one you pick depends on how much you care about your program looking good, as opposed to merely working.

One. Starting with the code you wrote, we could change it to:

while (curr_char != EOF)
{
curr_char = getc(original_file);
if(curr_char == EOF) break;
putc(curr_char, second_file);
}

Here, we explicitly test to see if the character is EOF, immediately after reading it, before writing it. If it's EOF, we break out of the loop early. This will work, but it's ugly: there are two different places where we test for EOF, and one of them never "fires". (Also, as a commentator reminded me, there's the problem that the first time through the loop, we're testing curr_char before we've ever set it.)

Two. You could rearrange it like this:

curr_char = getc(original_file);
while (curr_char != EOF)
{
putc(curr_char, second_file);
curr_char = getc(original_file);
}

Here, we read an initial character, and as long as it's not EOF, we write it and read another. This will work just fine, but but it's still a little bit ugly, because this time there are two different places where we read the character.

Three. You could rearrange it like this:

while ((curr_char = getc(original_file)) != EOF)
{
putc(curr_char, second_file);
}

This is the conventional way of writing a character-copying loop in C. The call to getc and the assignment to curr_char are buried inside of the controlling expression of the while loop. It depends on the fact that in C, an assignment expression has a value just like any other expression. That is, the value of the expression a = b is whatever value we just assigned to a (that is, b's value). So the value of the expression curr_char = getc(original_file) is the character we just read. So when we say while ((curr_char = getc(original_file)) != EOF), what we're actually saying is, "Call getc, assign the result to curr_char, and if it's not equal to EOF, take another trip around the loop."

(If you're still having trouble seeing this, I've written other explanations in these notes and this writeup.)

This code is both good and bad. It's good because we've got exactly one place we read characters, one place we test characters, and one place we write characters. But it's a little bit bad because, let's admit it, it's somewhat cryptic at first. It's hard to think about that assignment-buried-inside-the-while-condition. It's code like this that gives C a reputation as being full of obscure gobbledegook.

But, at least in this case, it really is worth learning the idiom, and becoming comfortable with it, because the reductions to just one read and one test and one write really are virtues. It doesn't matter so much in a trivial case like this, but in real programs which are complicated for other reasons, if there's some key piece of functionality that happens in two different places, it's extremely easy to overlook this fact, and to make a change to one of them but forget to make it to the other.

(In fact, this happened to me just last week at work. I was trying to fix a bug in somebody else's code. I finally figured out that when the code did X, it was inadvertently clearing Y. I found the place where it did X, and I added some new code to properly recreate Y. But when I tested my fix, it didn't work! It turned out there were two separate places where the code did X, and I had found and fixed the wrong one.)

Finally, here's an equivalently minimal but unconventional way of writing the loop:

while (1)
{
curr_char = getc(original_file);
if(curr_char == EOF) break;
putc(curr_char, second_file);
}

This is kind of like number 1, but it gets rid of the redundant condition in the while loop, and replaces it with the constant 1, which is "true" in C. This will work just fine, too, and it shares the virtue of having one read, one test, and one write. It actually ends up doing exactly the same operations and in exactly the same order as number 3, but by being laid out linearly it may be easier to follow.

The only problem with number 4 is that it's an unconventional, "break in the middle" loop. Personally, I don't have a problem with break-in-the-middle loops, and I find they come up from time to time, but if I wrote one and someone said "Steve, that's ugly, it's not an idiom anyone recognizes, it will confuse people", I'd have to agree.

P.S. I have replaced your calls to fgetc and fputc with the more conventional getc and putc. I'm not sure who told you to use fgetc and fputc, and there are obscure circumstances where you need them, but they're so rare that in my opinion one might as well forget that the "f" variants exist, and always use getc and putc.

How to use EOF to run through a text file in C?

How you detect EOF depends on what you're using to read the stream:

function                  result on EOF or error                    
-------- ----------------------
fgets() NULL
fscanf() number of succesful conversions
less than expected
fgetc() EOF
fread() number of elements read
less than expected

Check the result of the input call for the appropriate condition above, then call feof() to determine if the result was due to hitting EOF or some other error.

Using fgets():

 char buffer[BUFFER_SIZE];
while (fgets(buffer, sizeof buffer, stream) != NULL)
{
// process buffer
}
if (feof(stream))
{
// hit end of file
}
else
{
// some other error interrupted the read
}

Using fscanf():

char buffer[BUFFER_SIZE];
while (fscanf(stream, "%s", buffer) == 1) // expect 1 successful conversion
{
// process buffer
}
if (feof(stream))
{
// hit end of file
}
else
{
// some other error interrupted the read
}

Using fgetc():

int c;
while ((c = fgetc(stream)) != EOF)
{
// process c
}
if (feof(stream))
{
// hit end of file
}
else
{
// some other error interrupted the read
}

Using fread():

char buffer[BUFFER_SIZE];
while (fread(buffer, sizeof buffer, 1, stream) == 1) // expecting 1
// element of size
// BUFFER_SIZE
{
// process buffer
}
if (feof(stream))
{
// hit end of file
}
else
{
// some other error interrupted read
}

Note that the form is the same for all of them: check the result of the read operation; if it failed, then check for EOF. You'll see a lot of examples like:

while(!feof(stream))
{
fscanf(stream, "%s", buffer);
...
}

This form doesn't work the way people think it does, because feof() won't return true until after you've attempted to read past the end of the file. As a result, the loop executes one time too many, which may or may not cause you some grief.

Append to the end of a file in C

Open with append:

pFile2 = fopen("myfile2.txt", "a");

then just write to pFile2, no need to fseek().



Related Topics



Leave a reply



Submit