题
我正在编写一个程序,该程序应该读取两个可以包含换行符和各种其他字符的字符串。因此,我使用 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 可能不是正确的函数,或者我尝试错误。假设这甚至是可能的。
解决方案
从终端收到EOF后,您将不会收到任何其他数据。没有办法取消输入 - 文件的结尾就是结束。
因此,您应该定义每个变量在单独的行上输入,并让用户按Enter键而不是EOF。您仍然需要检查是否已收到eof,因为这意味着用户实际输入了EOF,而您将看不到任何其他内容 - 在这种情况下,您需要突破循环并打印错误消息。
其他提示
EOF
不是一个 特点 - 这是输入函数返回的一个特殊值,用于指示 状况, ,表明已到达该输入流上的“文件结尾”。正如马丁诉。Löwis 表示,一旦发生“文件结尾”情况,就意味着该流上将不再有可用的输入。
造成混乱的原因是:
- 当“文件”是交互式终端时(例如,Ctrl-Z 或 Ctrl-D);和
- 这
EOF
value 是可以返回的值之一getchar()
函数族。
您将需要使用实际的字符值来分隔输入 - ASCII nul 字符 '\0'
如果它不能在输入本身中显示为有效值,则可能是一个不错的选择。
我在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,因为终端输入缓冲区不为空。
您可以使用空字符('\ 0'
)来分隔变量。各种UNIX工具(例如 find
)能够以这种方式分离它们的输出项,这表明它是一种相当标准的方法。
这样做的另一个好处是你可以将流读入一个缓冲区然后创建一个 char *
的数组来指向各个字符串,每个字符串都将正确 '\ 0'
- 终止,无需手动更改缓冲区中的任何内容。这意味着更少的内存分配开销,这可能会使您的程序运行速度明显更快,具体取决于您正在读取的变量数量。当然,只有在需要同时将所有变量保存在内存中时才需要这样做&#8212;如果你一次一个地处理它们,你就没有这个特别的优势。
EOF根本不可能实现你的目标。
虽然它在某些方面表现得像个,但EOF不是流中的字符,而是表示流的 end 的环境定义的宏。我还没有看到你的代码,但我知道你做的是这样的:
while ((c=getchar()) != EOF) {
// do something
}
while ((c=getchar()) != EOF) {
// do something else
}
第一次键入EOF字符时,要结束第一个字符串,流将不可撤销地关闭。也就是说,流的状态是它已关闭。
因此,第二个while循环的内容永远不会运行。
而不是停止在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) ] $
如何在程序中输入null?
您可以使用以下方法实现-print0函数:
putchar(0);
这将打印ASCII字符'\ 0'到sdtout。