我写了一个程序,它将读取并输出自己的源文件的内容。我的目的主要是学习如何使用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:替换字符),但我似乎无法输入。
我的问题是,为什么它不会在最后的结束大括号结束程序而是打印一堆替换字符?
答案 0 :(得分:3)
循环中的顺序不正确。您应该在存储和打印字符值之前检查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
为 false 。除非在dostuff
中进行无法预料的修改,否则循环将以i = N
终止。
同样,eval在增量步骤之后完成,在你的情况下如此:
for(i=0; fileContents[i] != EOF; i++)
在每次进入循环体之前评估控制表达式fileContents[i] != EOF
。增量表达式在循环体后发生,但在下一次评估control-expression之前发生。在循环体内,您将EOF
存储在使用当前值i
索引的广告位中。然后身体结束,i
递增,然后你才检查一个你没有写过任何东西的插槽(还)。这一直持续到某一点,如果您(非)幸运,您会在新更新的EOF
索引中发现i
等效值。因此你终止了(但很可能,你很久以前就崩溃了。)