Question

Hello i had a simple copy file program in C but i cant explain why i get different output in the destination file when i use the 2nd method. The correct output with for loop:

I am the worst programmer in the world!
:D
 And this is bla bla bla bla
 more bla bla bla...

BUT with while loop a random char is generated in EOF:

I am the worst programmer in the world!
:D
 And this is bla bla bla bla
 more bla bla bla...


The code is

int main()
{
int i;
char ch;
create_files();
FILE *src = fopen("best.txt", "r");
FILE *dst = fopen("copied.txt", "w");
for(i=getc(src); i!=EOF; i=getc(src))  //correct copy
    {
        putc(i, dst);
    }

/* while(!feof(src))                  //woot?
    {
        ch=fgetc(src);
        fputc(ch,dst);
    }*/

fclose(dst);
fclose(src);
return 0;
}

void create_files()
{
    FILE *fp;
    fp = fopen("best.txt","w");
    fprintf(fp,"I am the worst programmer in the world!\n:D\n And this is bla bla bla bla\n more bla bla bla...\n");
    fclose(fp);
}

i ve used both fputc or putc and fgetc or getc and still the same. Did i forget something?

Was it helpful?

Solution

What

while (!feof(src)) {
    ch=fgetc(src);
    fputc(ch,dst);
}

does, is:

  1. check for EOF
  2. read a character, possibly causing EOF
  3. output the character just read, without checking for EOF.

When EOF occurs, (3) is still executed before the check in (1) in the next iteration. The special value EOF is converted to a char and output.

The correct loop is

while ((ch = fgetc(src)) != EOF)
    fputc(ch, dst);

assuming you give ch the type int, because a char cannot represent EOF. Note the assignment within the check; some programmers will tell you that's ugly, but so many use it that you might as well get used to it. Your variant for loop is correct as well.

(Aside 1: fputc is equivalent to putc and fgetc to getc, as long as you don't try to use them in a function pointer context.)

(Aside 2: your while loop also doesn't check for stream errors, while checking for EOF returns catches that as well.)

OTHER TIPS

The first loop fetches the character (possibly detecting the EOF) and then checks the value didn't detect an EOF and possibly executes the block writing the character (until all characters have been read).

The second loop checks to see if an EOF was detected, fetches the character (possibly detecting an EOF), writes the character (without regard as to what it might be), and possibly continues onto the next character (if EOF wasn't detected).

In the second loop, you write the character before checking if it is a EOF.

The while loop gives you a random character because EOF isn't actually flagged until a read fails. So what's happening in your while loop isyou do a read, fgetc fails, sets EOF, and returns a duff value back to you, which you then print.

A better way to structure the while loop would be:

ch=fgetc(src);
while (!feof(src)) {
   fputc(ch,dst);
   ch=fgetc(src);
}

Your while loop has an off-by-one error. It reads/writes an extra character, which is where that bonus is coming from - you wrote the EOF value returned by fgetc() into the output file!

Edit

Looks like this isn't the actual problem, but I'll keep the answer as an advice.


The only thing I noticed is:

char ch;

Depending on your system, char can be signed or unsigned, enough to hold a EOF or not enough. Your while loop is probably demonstrating that your OS fits in the latter case.

Use int instead and give it a try.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top