如何正确使用EOF?

时间:2018-07-01 05:26:50

标签: c io eof

我对EOF有疑问。

首先,我正在编写一个简单的程序来处理/打印用户的输入。

但是,程序也会在输出中复制EOF。

例如,我的操作系统是Window,而我按顺序键入(Enter-> cntrl + z-> Enter)时,我的EOF可以工作。如果我输入“ Hello” + Enter + EOF组合键,则输出将在复制的用户输入的末尾打印出奇怪的字母('?')。

enter image description here

如何摆脱“?”在输出的末尾,为什么会发生?

#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]) != '\0')
        i++;
}

4 个答案:

答案 0 :(得分:4)

您忘记了NUL终止onClick(e, stateKey){ this.setState({[stateKey]: e.target.value}); } 。因此,您可以在复制期间调用未定义行为。使用以下代码获取输入:

origin

还将打印代码更改为:

for(i = 0; i < 9 && (c = getchar()) != EOF; ++i) /* `i < 9` to prevent array overruns */
{
    origin[i] = c;
}
origin[i] = '\0'; /* NUL-terminate your string */

答案 1 :(得分:3)

该问题根本与EOF无关,代码中存在多个问题,导致潜在的不确定行为和不良副作用:

  • 读取循环一直持续到文件末尾:如果输入流的长度超过10个字节,则代码将导致缓冲区溢出,并存储origin数组末尾的字节。这是行为未定义的第一种情况。
  • 本地数组origin未初始化,因此其内容不确定。从stdin读取字节后,不要在其中存储空终止符。
  • copy函数中,您依靠空终止符停止复制循环,但是由于没有终止符存储在其中,因此在复制从stdin读取的所有字节之后,您可以访问未初始化的内容。空终止符测试与while((to[i] = from[i]) != '\0')中的赋值结合在一起。访问未初始化的数据具有未定义的行为。此外,您将继续从origin进行读取,直到找到一个空终止符为止,如果最终读取结果超出了数组末尾,则会导致进一步的未定义行为,而在copied末尾进行写入时甚至会导致更多不确定的行为。数组。
  • 最终循环输出copied数组的所有10个元素。
  • 即使数组origin偶然在末尾包含空字节,也可以防止copy函数中未定义的行为。输出循环仍将输出有趣的字符,因为您不会在空终止符处停止,而是将其打印到stdout,并且在此之后在copied的末尾读取未初始化的内容时再次具有未定义的行为。
  • 还要注意,main(不带参数)的原型是int main(void)。您使用的没有返回类型的语法在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] = '\0';

    copy(copied, origin);

    for (i = 0; copied[i] != '\0'; i++) {
        putchar(copied[i]);
    }

    return 0;
}

void copy(char to[], char from[]) {
    int i;

    i = 0;
    while ((to[i] = from[i]) != '\0')
        i++;
}

答案 2 :(得分:1)

您将无条件输出数组的所有10个成员。
您可以通过在字母末尾附加常用的'\0'来解决问题。

origin[i] = '\0';

读完后。

最后输出直到该标记,而不是所有内容

for(i = 0; copied[i]!='\0'; i++)

您可以假设数组足够大以保留输入(包括添加的'\0')。但是,您应该对此加以保护,例如,对任何循环使用双重条件,检查是否禁止访问最大允许的数组索引。

答案 3 :(得分:0)

您使用的是IDE(可能是CodeBlocks),该IDE在后续的IO操作之间使用页面缓冲区,这就是您真正获得输出的原因。

接下来,您将强制在循环输出中打印数组的所有十个元素,这是不好的编码习惯。

这个简单的代码片段可以帮助您

scanf("%10[^\n]s",input);

使用它来读取文件./youpro

感谢David C. Rankin在评论中提及错误。