while ( !feof (file) ) is always wrong?, because feof(file)
does not test true
until EOF
is encountered. If you are controlling your loop with:
while ( !feof (file) ) {
/* read statement */
/* write statement */
}
Your read statement will read the last line (or character) in the file, leaving the next read to trigger EOF
, however, the current read succeeded and did not set EOF
, your write completes OK.
What happens next?
You test feof (file)
which is still false
, so !feof (file)
tests true
and you start processing the statements within the loop again. Your read fails because the read pointer was sitting right before EOF
, you have an invalid read, then you then call your write statement invoking Undefined Behavior by writing an indeterminate value to your file. One you trigger Undefined Behavior, your program can do anything from appearing to complete successfully or SEGFAULT or anything in between.
Instead, simply control your read loop with fgets
itself. That way, only if fgets
succeeds will you enter your loop and write values to your file, e.g.
#include <stdio.h>
#define MAXC 100 /* if you need a constant, #define one (or more) */
#define DPATH "file2.txt"
int main (int argc, char **argv) {
FILE *fptr1 = NULL, /* initialize all variables (good practice) */
*fptr2 = NULL;
char data[MAXC] = "";
/* open/validate file for reading (default stdin) */
fptr1 = argc > 1 ? fopen (argv[1], "r") : stdin;
if (fptr1 == NULL) {
fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
return 1;
}
/* open/validate file for writing */
fptr2 = fopen (DPATH, "w");
if (fptr2 == NULL) {
fprintf (stderr, "error: file open failed '%s'.\n", DPATH);
return 1;
}
/* read contents from file */
while (fgets (data, sizeof data, fptr1)) { /* read 99-char blocks */
printf ("%s", data); /* (optional) output to stdout */
fputs (data, fptr2); /* write block to fptr2 */
}
printf ("\nContents copied to %s\n", DPATH);
fclose(fptr1);
if (fclose(fptr2) == EOF) /* always validate close-after-write */
perror ("fclose-fptr2");
return 0;
}
note: don't use magic numbers or hardcoded values in your code, instead, if you need constants #define
them (or for numeric constants you can also use a global enum
to define them).
*Example Input File**
$ cat dat/captnjack.txt
This is a tale
Of Captain Jack Sparrow
A Pirate So Brave
On the Seven Seas.
Check if output file exists:
$ ls -al file2.txt
ls: cannot access 'file2.txt': No such file or directory
Example Use/Output
$ ./bin/fgets_copy_file <dat/captnjack.txt
This is a tale
Of Captain Jack Sparrow
A Pirate So Brave
On the Seven Seas.
Contents copied to file2.txt
Check file2.txt
:
$ cat file2.txt
This is a tale
Of Captain Jack Sparrow
A Pirate So Brave
On the Seven Seas.
Look things over and let me know if you have further questions.