繁体   English   中英

如何正确使用EOF?

[英]How to properly using EOF?

我对EOF有疑问。

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

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

例如,我的操作系统是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]) != '\0')
        i++;
}

你忘了NUL终止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 */

同时将打印代码更改为:

for(i = 0; copied[i] != '\0'; i++) /* Print until a NUL-terminator */
    putchar(copied[i]); 

问题根本与EOF无关,您的代码中存在多个问题,导致潜在的未定义行为和不必要的副作用:

  • 读取循环一直持续到文件末尾:如果输入流超过10个字节,代码将导致缓冲区溢出,将字节存储在origin数组的末尾之外。 这是未定义行为的第一种情况。
  • 本地数组origin是未初始化的,因此其内容是不确定的。 在从stdin读取的字节之后,不存储空终止符。
  • copy函数中,您依赖空终止符来停止复制循环,但由于没有存储复制循环,因此在复制从stdin读取的所有字节后,您将访问未初始化的内容。 null终止符测试与while((to[i] = from[i]) != '\\0')的赋值相结合。 访问未初始化的数据具有未定义的行为。 此外,您继续从origin读取,直到找到空终止符,如果最终读取超出数组末尾,则会导致进一步的未定义行为,当写入超出copied数组末尾时更是如此。
  • 最后一个循环输出copied数组的所有10个元素。
  • 即使数组origin可能在最后包含空字节,从而防止了copy函数中的未定义行为。 输出循环仍然会输出有趣的字符,因为您不会在null终止符处停止,而是将其打印到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++;
}

您无条件地输出阵列的所有10个成员。
您可以通过在字母末尾附加经常使用的'\\0'来输出。
有了

origin[i] = '\0';

读完后。

最后输出直到那个标记,而不是一切

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

这样可以保证阵列足够大以保持输入(包括添加的'\\0' )。 但是,您应该对此进行保护,例如,通过对任何循环使用双重条件,检查是否允许访问beyound允许的最高数组索引。

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

接下来,您将强制在输出for循环中打印数组的所有十个元素,这是错误的编码实践。

这个简单的代码片段可以帮到你

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

用它来读取文件./youpro <file_name_where_to_fetch_input中的输入

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM