如何正确使用 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++;
}