简体   繁体   中英

Odd output when reading and printing from file in C

I wrote a program that will read from and output the contents of its own source file. My purpose is primarily just learning how to use I/O streams and the "FILE" type. I wrote the program in a plain text document on Linux Ubuntu 14.04 and used the terminal to compile and run the program. This is the content of the terminal from compilation to finish:

joseph@ubuntu:~/Desktop$ gcc test.c
joseph@ubuntu:~/Desktop$ ./a.out

File Opened

#include<stdio.h>
#define fileLocation ("/home/joseph/Desktop/test.c")
#define MAXREAD 1000

int main(void)
{
    char fileContents[MAXREAD];
    int i;

    FILE *tf;
    tf = fopen(fileLocation, "r");

    printf("File Opened\n");
    for(i=0;fileContents[i] != EOF; i++)
    {
        fileContents[i] = fgetc(tf);
        printf("%c", fileContents[i]);
    }
    fclose(tf);
    printf("\nFile Closed\n");
    return 0;
}
************************************************************

File Closed

The * symbols are actually the Unicode (0+FFFD: Replacement Character) but I can't seem to type that.

My question is, why doesn't it end the program at the final closing curly brace and instead, print a bunch of replacement characters?

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 an EOF equivalent value at your newly-updated i index. And thus you terminate (but most likely, you've crashed long before then).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM