[英]Odd output when reading and printing from file in C
我寫了一個程序,它將讀取並輸出自己的源文件的內容。 我的目的主要是學習如何使用I / O流和“FILE”類型。 我在Linux Ubuntu 14.04上的純文本文檔中編寫了程序,並使用終端編譯和運行程序。 這是從編譯到完成的終端內容:
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
*符號實際上是Unicode(0 + FFFD:替換字符),但我似乎無法輸入。
我的問題是,為什么它不會在最后的結束大括號結束程序而是打印一堆替換字符?
循環中的順序不正確。 在存儲和打印字符值之前,您應該檢查EOF。 您還應該確保不會超越數組邊界。
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;
}
您的代碼版本包括在char
打印錯誤存儲的EOF(這本身就是另一個問題,但首先不存儲它可以避免)。 但這遠遠不是你困境的結束。 用於繼續for循環的條件邏輯是錯誤的。 實際上,由於你從不初始化fileContents[]
,它實際上會調用未定義的行為 。 每次迭代,您都要檢查一個尚未編寫的數組槽,也不會進行初始化。 繼續閱讀如何/為什么 。
為什么要繼續打印 ?
在每次循環迭代之前計算控制表達式fileContents[i] != EOF
。 增量表達式i++
在每次迭代之后但在下一次控制條件評估之前執行。 從標准:
該聲明
for ( clause-1 ; expression-2 ; expression-3 ) statement
行為如下:表達式
expression-2
是在每次執行循環體之前計算的控制表達式。 在每次執行循環體之后,expression-3
被評估為void表達式。 如果clause-1
是一個聲明,它聲明的任何標識符的范圍是聲明的剩余部分和整個循環,包括其他兩個表達式; 它是在控制表達式的第一次評估之前按執行順序到達的。 如果clause-1
是表達式,則在第一次控制表達式求值之前將其計算為void表達式。
坦率地說,你剛剛保存在fileContents[i]
的EOF永遠不會被檢查,因為i
在下一次評估之前會增加。 根據以上描述,這是有意義的。 這就是簡單循環的原因:
for (i=0; i<N; ++i)
dostuff;
退出時i < N
為假 。 除非在dostuff
無法預料的修改, dostuff
循環將以i = N
結束。
同樣,eval在增量步驟之后完成,因此在您的情況下:
for(i=0; fileContents[i] != EOF; i++)
在每次進入循環體之前評估控制表達式fileContents[i] != EOF
。 循環體后增量表達發生,但控制表達的接下來的評測之前 。 在循環體內,您將EOF
存儲在以當前值i
索引的槽中。 然后身體完成, i
會增加,然后才會檢查你沒有寫任何東西的插槽(還)。 這一直持續到某一點,如果你(非)幸運,你會在新更新的i
索引中發現EOF
等值。 因此你終止(但很可能,你在此之前已經很久就崩潰了)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.