4

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

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

我试图用while (getchar() != '\n');几个类似的变化来清理缓冲区,但似乎没有任何帮助。所有的清理尝试都导致了一个无限循环,如果不清理,添加第二个变量是不可能的。

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

在为此苦苦挣扎了几个小时后,我开始变得有些绝望。

代码:

#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);
}
4

7 回答 7

12

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

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

于 2009-10-25T21:20:25.960 回答
2

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

产生混淆的原因是:

  • 当“文件”是交互式终端(例如 Ctrl-Z 或 Ctrl-D)时,许多终端类型会识别一个特殊的击键来表示“文件结束”;和
  • EOF值是函数族可以返回的值之一getchar()

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

于 2009-10-25T21:32:51.473 回答
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。

于 2009-10-25T22:26:59.437 回答
0

你正在尝试的东西对于 EOF 来说是根本不可能的。

尽管它在某些方面表现得像一个字符,但 EOF 不是流中的一个字符,而是一个环境定义的宏,表示流的结尾。我还没有看到你的代码,但我猜你正在做的是这样的:

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

当您第一次键入 EOF 字符以结束第一个字符串时,流将不可撤销地关闭。即流的状态是关闭。

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

于 2009-10-25T21:30:43.910 回答
0

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

这样做的另一个优点是您可以将流读入单个缓冲区,然后创建一个char*s 数组以指向各个字符串,并且每个字符串都将正确'\0'终止,而无需手动更改缓冲区中的任何内容。这意味着更少的内存分配开销,这可能会使您的程序运行得更快,具体取决于您正在读取的变量数量。当然,这仅在您需要同时将所有变量保存在内存中时才有必要——如果您一次处理一个变量,您就不会获得这种特殊优势。

于 2009-10-25T21:30:51.820 回答
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 之后的 Ctrl+D)
输入 b:三
线条
现在(ENTER + Ctrl+D)
a是[两个
行(下一个 ENTER 之后的 Ctrl+D)
]; b是[三
线条
现在(ENTER + Ctrl+D)
]
$
于 2009-10-25T21:50:39.300 回答
0

如何在程序中输入 null?

您可以使用以下方法实现 -print0 功能:

putchar(0);

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

于 2009-10-26T07:01:01.197 回答