我有以下程序:
int main(int argc, char *argv[])
{
char ch1, ch2;
printf("Input the first character:"); // Line 1
scanf("%c", &ch1);
printf("Input the second character:"); // Line 2
ch2 = getchar();
printf("ch1=%c, ASCII code = %d\n", ch1, ch1);
printf("ch2=%c, ASCII code = %d\n", ch2, ch2);
system("PAUSE");
return 0;
}
正如上述代码的作者所解释的那样:
该程序将无法正常工作,因为在第1行,当用户按Enter键时,它将在输入缓冲区中保留2个字符:Enter key (ASCII code 13)
和\n (ASCII code 10)
。因此,在第2行,它将读取\n
并且不会等待用户输入字符。
getchar()
(ch2 = getchar();
)不会读取Enter key (13)
而不是\n
字符?
接下来,作者提出了两种解决此类问题的方法:
使用fflush()
写一个这样的函数:
void
clear (void)
{
while ( getchar() != '\n' );
}
此代码实际上有效。但我无法解释自己它是如何运作的?因为在while语句中,我们使用getchar() != '\n'
,这意味着读取除'\n'
之外的任何单个字符?如果是这样,在输入缓冲区中仍然是'\n'
字符?
答案 0 :(得分:74)
程序无法正常工作,因为在第1行,当用户按下Enter时,它将在输入缓冲区中保留2个字符:输入密钥(ASCII代码13)和\ n(ASCII代码10)。因此,在第2行,它将读取\ n并且不会等待用户输入字符。
您在第2行看到的行为是正确的,但这不是正确的解释。对于文本模式流,平台使用的行结尾无关紧要(无论是回车(0x0D)+换行(0x0A),裸CR还是裸LF)。 C运行时库将为您解决这个问题:您的程序只会看到'\n'
换行符。
如果您输入了一个字符并按了Enter键,则第1行将读取该输入字符,然后第2行将读取'\n'
。请参阅comp.lang.c中的I'm using scanf %c
to read a Y/N response, but later input gets skipped.。常见问题。
关于建议的解决方案,请参阅(再次从comp.lang.c FAQ):
fflush(stdin)
work? fflush
won't work, what can I use to flush input? 基本上说明了唯一的便携式方法:
int c;
while ((c = getchar()) != '\n' && c != EOF) { }
您的getchar() != '\n'
循环有效,因为一旦您调用getchar()
,返回的字符就已从输入流中删除。
此外,我觉得有义务阻止您完全使用scanf
:Why does everyone say not to use scanf
? What should I use instead?
答案 1 :(得分:37)
你也可以这样做:
fseek(stdin,0,SEEK_END);
答案 2 :(得分:11)
行:
int ch;
while ((ch = getchar()) != '\n' && ch != EOF)
;
不会只读取换行符之前的字符('\n'
)。它读取流中的所有字符(并丢弃它们)直到并包括下一个换行符(或遇到EOF)。为了使测试成立,它必须首先读取换行符;因此,当循环停止时,换行符是最后读取的字符,但它已被读取。
至于为什么它读取换行而不是回车,这是因为系统已将回报转换为换行符。当按下enter时,表示该行的结束...但该流包含换行,因为这是系统的正常行尾标记。这可能取决于平台。
此外,在输入流上使用fflush()
并不适用于所有平台;例如,它通常不适用于Linux。
答案 3 :(得分:10)
清理到您已尝试部分阅读的行尾的便携式方法是:
int c;
while ( (c = getchar()) != '\n' && c != EOF ) { }
这将读取并丢弃字符,直到它获得\n
信号结束文件。如果输入流在行结束之前关闭,它还会检查EOF
。 c
的类型必须为int
(或更大),才能保留值EOF
。
没有可移植的方法来确定当前行之后是否还有其他行(如果没有,则getchar
将阻止输入)。
答案 4 :(得分:8)
但我无法解释自己是如何运作的?因为在while语句中,我们使用
getchar() != '\n'
,这意味着读取除'\n'
之外的任何单个字符?如果是这样,在输入缓冲区仍然是'\n'
字符??? 我误解了什么吗?
您可能没有意识到的是,在 getchar()
从输入缓冲区中删除字符后,会发生比较。因此,当您到达'\n'
时,它会被消耗,然后就会突破循环。
答案 5 :(得分:6)
你可以尝试
scanf("%c%*c", &ch1);
其中%* c接受并忽略换行符
还有一种方法 而不是调用未定义行为的fflush(stdin),你可以编写
while((getchar())!='\n');
不要忘记while循环后的分号
答案 6 :(得分:4)
尚未提及的另一个解决方案是使用: 倒带(标准输入);
答案 7 :(得分:1)
unsigned char a=0;
if(kbhit()){
a=getch();
while(kbhit())
getch();
}
cout<<hex<<(static_cast<unsigned int:->(a) & 0xFF)<<endl;
-OR -
使用可能使用_getch_nolock()
.. ???
答案 8 :(得分:1)
我在尝试实施解决方案时遇到问题
while ((c = getchar()) != '\n' && c != EOF) { }
我发布了一些调整&#39;代码B&#39;对于任何可能遇到同样问题的人。
问题在于该计划让我抓住了这个&#39; \ n&#39;字符,独立于输入字符,这是给我问题的代码。
代码A
int y;
printf("\nGive any alphabetic character in lowercase: ");
while( (y = getchar()) != '\n' && y != EOF){
continue;
}
printf("\n%c\n", toupper(y));
调整是为了抓住&#39;在评估while循环中条件之前的(n-1)字符,这里是代码:
代码B
int y, x;
printf("\nGive any alphabetic character in lowercase: ");
while( (y = getchar()) != '\n' && y != EOF){
x = y;
}
printf("\n%c\n", toupper(x));
可能的解释是,对于要打破的while循环,它必须分配值&#39; \ n&#39;到变量y,所以它将是最后指定的值。
如果我错过了解释的内容,代码A或代码B,请告诉我,我几乎不是新的。
希望它可以帮助某人
答案 9 :(得分:0)
简短,可移植并在stdio.h中声明
stdin = freopen(NULL,"r",stdin);
当stdin上没有任何东西可以像下面这个众所周知的行一样冲洗时,不会挂在无限循环中:
while ((c = getchar()) != '\n' && c != EOF) { }
有点贵,所以不要在需要反复清除缓冲区的程序中使用它。
从同事那里偷走了:))
答案 10 :(得分:0)
我很惊讶没有人提及此事
scanf("%*[^\n]");
答案 11 :(得分:0)
简而言之。把线...
while ((c = getchar()) != '\n') ;
...在读取输入的行之前是唯一有保证的方法。 它仅使用核心 C 功能(根据 K&R 的“C 语言的传统核心”),这些功能保证在所有情况下都能与所有编译器一起使用。
实际上,您可以选择添加提示,要求用户按 ENTER 继续(或者,可选择按 Ctrl-D 或任何其他按钮来完成或执行其他代码):
printf("\nPress ENTER to continue, press CTRL-D when finished\n");
while ((c = getchar()) != '\n') {
if (c == EOF) {
printf("\nEnd of program, exiting now...\n");
return 0;
}
...
}
还是有问题。用户可以多次按 ENTER。这可以通过向输入行添加输入检查来解决:
while ((ch2 = getchar()) < 'a' || ch1 > 'Z') ;
以上两种方法的结合理论上应该是防弹的。 在所有其他方面,@jamesdlin 的回答是最全面的。
答案 12 :(得分:-1)
char choice;
do{
printf("\n *");
printf("\n Do you want to continue? (y/n) ");
choice = getchar();
if(getchar() != '\n'){
fflush(stdin);
}
}while( choice != 'n' );
答案 13 :(得分:-1)
尝试一下:
stdin->_IO_read_ptr = stdin->_IO_read_end;