C中的EOF问题

时间:2009-10-25 21:16:20

标签: c string newline eof getchar

我正在编写一个程序,它应该读取两个可以包含换行符和其他各种字符的字符串。因此,我使用EOF(Ctrl-Z或Ctrl-D)结束字符串。

这适用于第一个变量,但是使用第二个变量,然而,这似乎有问题,因为显然某些东西卡在输入缓冲区中而用户无法输入任何内容。

我尝试使用while (getchar() != '\n');和几个类似的变体清理缓冲区,但似乎没有任何帮助。所有清洁尝试都导致无限循环,如果不进行清洁,则无法添加第二个变量。

这两个变量的字符都是在这样的循环中读取的:while((c = getchar()) != EOF),这表明它是我在缓冲区中停留的EOF。或者以其他方式影响程序的行为?我正在使用的逻辑有什么问题吗?

在经过几个小时的挣扎之后,我开始有点绝望了。

[编辑:在下方添加代码]

[编辑2:clearerr()似乎让这个EOF解决方案工作了。

它似乎以我在Linux下的原始形式运行,我昨天在Windows上试用它。]

代码:

#include <stdio.h>
#include <string.h>

int main(void)
{
    int x = 0;
    int c;
    char a[100];
    char b[100];

    printf("Enter a: ");
    while((c = getchar()) != EOF)
    {
        a[x] = c;
        x++;
    }
    a[x] = '\0';
    x = 0;

    /*while (getchar() != '\n'); - the non-working loop*/

    printf("\nEnter b: ");
    while((c = getchar()) != EOF)
    {
        b[x] = c;
        x++;
    }
    b[x] = '\0';

    printf("\n\nResults:\na: %s\n", a);
    printf("b: %s\n", b);

    return(0);
}

[编辑3:]

动态内存问题:

我的程序也应该处理超过100个字符的字符串。最初我打算通过动态内存分配解决这个问题,但是当我遇到上述无限循环和内存相关崩溃的问题时,我把它留了出去并切换到char [100]。

我认为我尝试的通常是这样的:

while((c = getchar()) != EOF)
{
  a = malloc(sizeof(char));
  a[x] = c;
  x++;
}

这是一种可能的(或明智的)方法吗?我正在尝试为那里处理的每个角色分配更多内存。独立。使用这样的代码(这个例子可能包含语法错误)我经历过崩溃,所以在我看来malloc可能不是正确的功能,或者我试错了。假设它甚至可能。

7 个答案:

答案 0 :(得分:9)

从终端收到EOF后,您将不会收到任何其他数据。没有办法取消输入 - 文件的结尾就是结束。

因此,您应该定义每个变量在单独的行上输入,并让用户按Enter键而不是EOF。您仍然需要检查是否已收到eof,因为这意味着用户实际输入了EOF,而您将看不到任何其他内容 - 在这种情况下,您需要突破循环并打印错误消息。

答案 1 :(得分:2)

EOF不是字符 - 它是一个特殊值,输入函数返回以指示条件,即“文件结束”已达到输入流。正如Martinv.Löwis所说,一旦发生“文件结束”条件,就意味着该流上不再有可用的输入。

出现混乱的原因是:

  • 当“文件”是交互式终端时(例如,Ctrl-Z或Ctrl-D),许多终端类型识别出用于发出“文件结束”信号的特殊按键;和
  • EOF值是getchar()系列函数可以返回的值之一。

您需要使用实际字符值来分隔输入 - 如果ASCII nul字符'\0'在输入中不能显示为有效值,则可能是一个不错的选择。

答案 2 :(得分:1)

我在linux框上运行代码,结果如下:

Enter a: qwer
asdf<Ctrl-D><Ctrl-D>
Enter b: 123
456<Ctrl-D><Ctrl-D>

Results:
a: qwer
asdf
b: 123
456

需要两个Ctrl-D,因为终端输入缓冲区不为空。

答案 3 :(得分:0)

EOF根本不可能实现你的目标。

虽然它在某些方面表现得像个,但EOF不是流中的字符,而是表示流的 end 的环境定义的宏。我还没有看到你的代码,但我知道你做的是这样的:

while ((c=getchar()) != EOF) {
    // do something
}
while ((c=getchar()) != EOF) {
    // do something else
}

第一次键入EOF字符时,要结束第一个字符串,流将不可撤销地关闭。也就是说,流的状态是它已关闭。

因此,第二个while循环的内容永远不会运行。

答案 4 :(得分:0)

您可以使用空字符('\0')来分隔变量。各种UNIX工具(例如find)能够以这种方式分离它们的输出项,这表明它是一种相当标准的方法。

这样做的另一个好处是你可以将流读入一个缓冲区然后创建一个char*的数组来指向各个字符串,每个字符串都将正确'\0' - 终止无需手动更改缓冲区中的任何内容。这意味着更少的内存分配开销,这可能会使您的程序运行速度明显更快,具体取决于您正在读取的变量数量。当然,只有当你需要同时在内存中保存所有变量时才需要这样做 - 如果你一次一个地处理它们,你就不会得到这个特别的优势。

答案 5 :(得分:0)

而不是停止在EOF读取输入 - 这不是一个字符 - 停止在ENTER。

while((c = getchar()) != '\n')
{
    if (c == EOF) /* oops, something wrong, input terminated too soon! */;
    a[x] = c;
    x++;
}

EOF是输入终止的信号。您几乎可以保证来自用户的所有输入都以'\ n'结尾:这是用户键入的最后一个键!!!


编辑:您仍然可以使用Ctrl-D和clearerr()来重置输入流。

#include <stdio.h>

int main(void) {
  char a[100], b[100];
  int c, k;

  printf("Enter a: "); fflush(stdout);
  k = 0;
  while ((k < 100) && ((c = getchar()) != EOF)) {
    a[k++] = c;
  }
  a[k] = 0;

  clearerr(stdin);

  printf("Enter b: "); fflush(stdout);
  k = 0;
  while ((k < 100) && ((c = getchar()) != EOF)) {
    b[k++] = c;
  }
  b[k] = 0;

  printf("a is [%s]; b is [%s]\n", a, b);
  return 0;
}
$ ./a.out
Enter a: two
lines (Ctrl+D right after the next ENTER)
Enter b: three
lines
now (ENTER + Ctrl+D)
a is [two
lines (Ctrl+D right after the next ENTER)
]; b is [three
lines
now (ENTER + Ctrl+D)
]
$

答案 6 :(得分:0)

  

如何在程序中输入null?

您可以使用以下方法实现-print0函数:

putchar(0);

这将打印ASCII字符'\ 0'到sdtout。