The order in your loop is incorrect. You should be checking for EOF before storing and printing your character value. You should also ensure you're not overstepping the array boundaries.
int main(void)
{
char fileContents[MAXREAD];
int i, c;
FILE *tf = fopen(fileLocation, "r");
if (tf == NULL)
{
perror(fileLocation);
return EXIT_FAILURE;
}
printf("File Opened\n");
for (i=0; i < MAXREAD && (c = fgetc(tf)) != EOF; ++i)
{
fileContents[i] = c;
fputc(fileContents[i], stdout);
}
fclose(tf);
printf("\nFile Closed\n");
return 0;
}
Your version of the code includes printing an incorrectly-stored EOF in a char
(which is itself another issue, but avoided by not storing it in the first place). But that is far form the end of your woes. Your conditional logic for continuing your for-loop is wrong. In fact, since you never initialize fileContents[]
, it actually invokes undefined behavior. With each iteration you're checking an array slot you haven't yet written, nor initialized. Read on for how/why.
Why do you keep printing?
The control expression, fileContents[i] != EOF
, is evaluated before each loop iteration. The increment expression, i++
, executes after each iteration, but before the next evaluation of the control conditional. From the standard:
The statement
for ( clause-1 ; expression-2 ; expression-3 ) statement
behaves as follows: The expression expression-2
is the controlling expression that is evaluated before each execution of the loop body. The expression expression-3
is evaluated as a void expression after each execution of the loop body. If clause-1
is a declaration, the scope of any identifiers it declares is the remainder of the declaration and the entire loop, including the other two expressions; it is reached in the order of execution before the first evaluation of the controlling expression. If clause-1
is an expression, it is evaluated as a void expression before the first evaluation of the controlling expression.
Putting it bluntly, the EOF you just saved in fileContents[i]
is never checked, because i
is incremented before the next evaluation. That makes sense from the above description. It is the very reason the simple loop:
for (i=0; i<N; ++i)
dostuff;
exits with i < N
being false. Barring unforeseen modification in dostuff
, the loop will terminate with i = N
.
Again, the eval is done after the increment step, and as such in your case:
for(i=0; fileContents[i] != EOF; i++)
The control expression fileContents[i] != EOF
is evaluated before each entry into the loop body. The increment expression happens after the loop body, but before the next evaluation of the control-expression. Within your loop body you store EOF
in the slot indexed with the current value of i
. Then the body finishes, i
is incremented, and only then do you check a slot that you didn't write anything upon (yet). This continues until some point, if you're (un)lucky, you discover anEOF
equivalent value at your newly-updated i
index. And thus you terminate (but most likely, you've crashed long before then).