如何正确使用 EOF?
How to properly using EOF?
我对 EOF 有疑问。
首先,我正在编写一个简单的程序,它是 coping/printing 用户的输入。
但是,程序还在输出中复制了 EOF。
例如,我的 O.S 是 Window,当我按顺序键入 (Enter -> cntrl + z -> Enter) 时,我的 EOF 有效。如果我输入 "Hello" + Enter + EOF 组合键,输出会在复制的用户输入末尾打印奇怪的字母('?')。
我怎样才能去掉'?'在输出的末尾,为什么会这样?
#include <stdio.h>
void copy(char to[], char from[]);
main()
{
int i;
int c;
char origin[10];
char copied[10];
for(i = 0; (c = getchar()) != EOF; ++i)
{
origin[i] = c;
}
copy(copied, origin);
for(i = 0; i < 10; i++)
putchar(copied[i]);
}
void copy(char to[], char from[])
{
int i;
i = 0;
while((to[i] = from[i]) != '[=10=]')
i++;
}
您忘记了 NUL 终止 origin
。所以你在复制过程中调用了未定义的行为。请改用以下代码获取输入:
for(i = 0; i < 9 && (c = getchar()) != EOF; ++i) /* `i < 9` to prevent array overruns */
{
origin[i] = c;
}
origin[i] = '[=10=]'; /* NUL-terminate your string */
也把打印代码改成:
for(i = 0; copied[i] != '[=11=]'; i++) /* Print until a NUL-terminator */
putchar(copied[i]);
您将无条件输出数组的所有 10 个成员。
您可以通过在要输出的字母末尾附加常用的 '[=12=]'
来修复。
用
origin[i] = '[=10=]';
阅读后。
最后输出到那个标记,而不是所有内容
for(i = 0; copied[i]!='[=11=]'; i++)
这使您假设数组足够大以保留输入(包括添加的 '[=12=]'
)。但是,您应该防止这种情况发生,例如,通过对任何循环使用双重条件,检查是否访问超出允许的最高数组索引。
您正在使用 IDE(可能是 CodeBlocks),它在后续 IO 操作之间使用页面缓冲区,这就是您实际获得输出的原因。
接下来,您在 for 循环的输出中强制打印数组的所有十个元素,这是糟糕的编码习惯。
这个简单的片段可以帮助您
scanf("%10[^\n]s",input);
使用它从文件中读取输入./youpro < file_name_where_to_fetch_input
感谢 David C. Rankin 在评论中指出错误。
该问题与 EOF
完全无关,您的代码中存在多个问题导致潜在的未定义行为和不需要的副作用:
- 读取循环一直持续到文件末尾:如果输入流的长度超过 10 个字节,代码将导致缓冲区溢出,存储超出
origin
数组末尾的字节。这是未定义行为的第一例。
- 本地数组
origin
未初始化,因此其内容不确定。在从 stdin
. 读取字节后,您不会将空终止符存储到其中
- 在
copy
函数中,您依靠空终止符来停止复制循环,但是由于 none 存储在那里,您在从 [=14= 读取所有字节后访问未初始化的内容] 已被复制。空终止符测试与 while((to[i] = from[i]) != '[=17=]')
中的赋值相结合。访问未初始化的数据具有未定义的行为。此外,您会一直从 origin
读取,直到找到空终止符,如果您最终读取超出数组末尾的内容,则会导致进一步的未定义行为,而在超出 copied
的末尾写入时更是如此数组。
- 最后一个循环输出
copied
数组的所有 10 个元素。
- 即使数组
origin
可能偶然在末尾包含空字节,从而防止 copy
函数中的未定义行为。输出循环仍会输出有趣的字符,因为您不会在空终止符处停止,而是将其打印到 stdout
,然后当您在 copied
末尾读取未初始化的内容时再次出现未定义的行为.
- 另请注意,不带参数的
main
的原型是 int main(void)
。您使用的没有 return 类型的语法在 70 和 80 年代很常见,但现在已经过时,不应再使用。
这是更正后的版本:
#include <stdio.h>
void copy(char to[], char from[]);
int main(void) {
int i;
int c;
char origin[10];
char copied[10];
for (i = 0; i < 10 - 1 && (c = getchar()) != EOF; i++) {
origin[i] = c;
}
origin[i] = '[=10=]';
copy(copied, origin);
for (i = 0; copied[i] != '[=10=]'; i++) {
putchar(copied[i]);
}
return 0;
}
void copy(char to[], char from[]) {
int i;
i = 0;
while ((to[i] = from[i]) != '[=10=]')
i++;
}
我对 EOF 有疑问。
首先,我正在编写一个简单的程序,它是 coping/printing 用户的输入。
但是,程序还在输出中复制了 EOF。
例如,我的 O.S 是 Window,当我按顺序键入 (Enter -> cntrl + z -> Enter) 时,我的 EOF 有效。如果我输入 "Hello" + Enter + EOF 组合键,输出会在复制的用户输入末尾打印奇怪的字母('?')。
我怎样才能去掉'?'在输出的末尾,为什么会这样?
#include <stdio.h>
void copy(char to[], char from[]);
main()
{
int i;
int c;
char origin[10];
char copied[10];
for(i = 0; (c = getchar()) != EOF; ++i)
{
origin[i] = c;
}
copy(copied, origin);
for(i = 0; i < 10; i++)
putchar(copied[i]);
}
void copy(char to[], char from[])
{
int i;
i = 0;
while((to[i] = from[i]) != '[=10=]')
i++;
}
您忘记了 NUL 终止 origin
。所以你在复制过程中调用了未定义的行为。请改用以下代码获取输入:
for(i = 0; i < 9 && (c = getchar()) != EOF; ++i) /* `i < 9` to prevent array overruns */
{
origin[i] = c;
}
origin[i] = '[=10=]'; /* NUL-terminate your string */
也把打印代码改成:
for(i = 0; copied[i] != '[=11=]'; i++) /* Print until a NUL-terminator */
putchar(copied[i]);
您将无条件输出数组的所有 10 个成员。
您可以通过在要输出的字母末尾附加常用的 '[=12=]'
来修复。
用
origin[i] = '[=10=]';
阅读后。
最后输出到那个标记,而不是所有内容
for(i = 0; copied[i]!='[=11=]'; i++)
这使您假设数组足够大以保留输入(包括添加的 '[=12=]'
)。但是,您应该防止这种情况发生,例如,通过对任何循环使用双重条件,检查是否访问超出允许的最高数组索引。
您正在使用 IDE(可能是 CodeBlocks),它在后续 IO 操作之间使用页面缓冲区,这就是您实际获得输出的原因。
接下来,您在 for 循环的输出中强制打印数组的所有十个元素,这是糟糕的编码习惯。
这个简单的片段可以帮助您
scanf("%10[^\n]s",input);
使用它从文件中读取输入./youpro < file_name_where_to_fetch_input
感谢 David C. Rankin 在评论中指出错误。
该问题与 EOF
完全无关,您的代码中存在多个问题导致潜在的未定义行为和不需要的副作用:
- 读取循环一直持续到文件末尾:如果输入流的长度超过 10 个字节,代码将导致缓冲区溢出,存储超出
origin
数组末尾的字节。这是未定义行为的第一例。 - 本地数组
origin
未初始化,因此其内容不确定。在从stdin
. 读取字节后,您不会将空终止符存储到其中
- 在
copy
函数中,您依靠空终止符来停止复制循环,但是由于 none 存储在那里,您在从 [=14= 读取所有字节后访问未初始化的内容] 已被复制。空终止符测试与while((to[i] = from[i]) != '[=17=]')
中的赋值相结合。访问未初始化的数据具有未定义的行为。此外,您会一直从origin
读取,直到找到空终止符,如果您最终读取超出数组末尾的内容,则会导致进一步的未定义行为,而在超出copied
的末尾写入时更是如此数组。 - 最后一个循环输出
copied
数组的所有 10 个元素。 - 即使数组
origin
可能偶然在末尾包含空字节,从而防止copy
函数中的未定义行为。输出循环仍会输出有趣的字符,因为您不会在空终止符处停止,而是将其打印到stdout
,然后当您在copied
末尾读取未初始化的内容时再次出现未定义的行为. - 另请注意,不带参数的
main
的原型是int main(void)
。您使用的没有 return 类型的语法在 70 和 80 年代很常见,但现在已经过时,不应再使用。
这是更正后的版本:
#include <stdio.h>
void copy(char to[], char from[]);
int main(void) {
int i;
int c;
char origin[10];
char copied[10];
for (i = 0; i < 10 - 1 && (c = getchar()) != EOF; i++) {
origin[i] = c;
}
origin[i] = '[=10=]';
copy(copied, origin);
for (i = 0; copied[i] != '[=10=]'; i++) {
putchar(copied[i]);
}
return 0;
}
void copy(char to[], char from[]) {
int i;
i = 0;
while ((to[i] = from[i]) != '[=10=]')
i++;
}