如何避免在getchar()中按Enter键仅读取单个字符?
在下一个代码中:如何避免在getchar()中按Enter键仅读取单个字符?,c,input,character,getchar,unbuffered,C,Input,Character,Getchar,Unbuffered,在下一个代码中: #include <stdio.h> int main(void) { int c; while ((c=getchar())!= EOF) putchar(c); return 0; } 但当我按“a”时,什么也没有发生,我可以写其他字母,只有当我按Enter键时,副本才会出现: 我该怎么做 我在Ubuntu下使用命令cc-o example.c进行编译。默认情况下,c库缓冲输出,直到看到返回。要立即打印结果,请使
#include <stdio.h>
int main(void) {
int c;
while ((c=getchar())!= EOF)
putchar(c);
return 0;
}
但当我按“a”时,什么也没有发生,我可以写其他字母,只有当我按Enter键时,副本才会出现:
我该怎么做
我在Ubuntu下使用命令
cc-o example.c
进行编译。默认情况下,c库缓冲输出,直到看到返回。要立即打印结果,请使用fflush
:
while((c=getchar())!= EOF)
{
putchar(c);
fflush(stdout);
}
getchar()是一个标准函数,在许多平台上,它要求您按ENTER键获取输入,因为平台会缓冲输入,直到按下该键。许多编译器/平台支持非标准的getch(),它不关心ENTER(绕过平台缓冲,将ENTER视为另一个键)。I/O是一个操作系统函数。在许多情况下,在按下ENTER键之前,操作系统不会将键入的字符传递给程序。这允许用户在将输入发送到程序之前修改输入(例如退格和重新键入)。在大多数情况下,这工作得很好,为用户提供了一致的界面,并且使程序不必处理这个问题。在某些情况下,程序需要在按键时从按键中获取字符 C库本身处理文件,并不关心数据如何进入输入文件。因此,语言本身无法在按键时获取按键;相反,这是特定于平台的。由于您尚未指定操作系统或编译器,我们无法为您查找
此外,标准输出通常会进行缓冲以提高效率。这是由C库完成的,因此有一个C解决方案,即
fflush(stdout)代码>在写入每个字符后。之后,字符是否立即显示取决于操作系统,但我熟悉的所有操作系统都会立即显示输出,因此这通常不是问题。这取决于您的操作系统,如果您处于类似UNIX的环境中,默认情况下启用ICANON标志,因此,输入被缓冲,直到下一个'\n'
或EOF
。通过禁用规范模式,您将立即获得字符。这在其他平台上也是可能的,但没有直接的跨平台解决方案
编辑:我看到你指定使用Ubuntu。我昨天刚刚发布了一些类似的内容,但请注意,这将禁用终端的许多默认行为
#include<stdio.h>
#include <termios.h> //termios, TCSANOW, ECHO, ICANON
#include <unistd.h> //STDIN_FILENO
int main(void){
int c;
static struct termios oldt, newt;
/*tcgetattr gets the parameters of the current terminal
STDIN_FILENO will tell tcgetattr that it should write the settings
of stdin to oldt*/
tcgetattr( STDIN_FILENO, &oldt);
/*now the settings will be copied*/
newt = oldt;
/*ICANON normally takes care that one line at a time will be processed
that means it will return if it sees a "\n" or an EOF or an EOL*/
newt.c_lflag &= ~(ICANON);
/*Those new settings will be set to STDIN
TCSANOW tells tcsetattr to change attributes immediately. */
tcsetattr( STDIN_FILENO, TCSANOW, &newt);
/*This is your part:
I choose 'e' to end input. Notice that EOF is also turned off
in the non-canonical mode*/
while((c=getchar())!= 'e')
putchar(c);
/*restore the old settings*/
tcsetattr( STDIN_FILENO, TCSANOW, &oldt);
return 0;
}
由于您使用的是Unix衍生工具(Ubuntu),这里有一种方法可以做到这一点——不推荐,但它可以工作(只要您能够准确地键入命令):
当您对程序感到厌烦时,使用中断停止程序
sh restore-sanity
- “echo”行将当前终端设置保存为一个shell脚本,该脚本将恢复这些设置
- “stty”行关闭大部分特殊处理(例如,Control-D无效),并在字符可用时立即向程序发送字符。这意味着你不能再编辑你键入的内容了
- “sh”行将恢复您原来的终端设置
如果“stty sane”能够充分准确地恢复您的设置以满足您的需要,您可以节省开支。“-g”的格式不能跨“stty”的版本移植(因此在Solaris 10上生成的内容在Linux上不起作用,反之亦然),但这个概念在任何地方都适用。“stty-sane”选项不是通用的(但在Linux上)。在Linux系统上,您可以使用stty
命令修改终端行为。默认情况下,终端将缓冲所有信息,直到按下Enter键,然后再将其发送到C程序
一个快速、肮脏且不特别可移植的示例,用于从程序本身内部更改行为:
#include<stdio.h>
#include<stdlib.h>
int main(void){
int c;
/* use system call to make terminal send all keystrokes directly to stdin */
system ("/bin/stty raw");
while((c=getchar())!= '.') {
/* type a period to break out of the loop, since CTRL-D won't work raw */
putchar(c);
}
/* use system call to set terminal behaviour to more normal behaviour */
system ("/bin/stty cooked");
return 0;
}
#包括
#包括
内部主(空){
INTC;
/*使用系统调用使终端将所有击键直接发送到stdin*/
系统(“/bin/stty raw”);
而((c=getchar())!='。){
/*键入一个句点以打破循环,因为CTRL-D不能正常工作*/
普查尔(c);
}
/*使用系统调用将终端行为设置为更正常的行为*/
系统(“/bin/stty”);
返回0;
}
请注意,这并不是最理想的,因为它只是假设stty-cooked
是程序退出时所需的行为,而不是检查原始终端设置。此外,由于在原始模式下跳过了所有特殊处理,许多键序列(如CTRL-C或CTRL-D)在没有在程序中显式处理的情况下实际上无法按预期工作
您可以manstty
来获得对终端行为的更多控制,具体取决于您想要实现什么。您可以包括“ncurses”库,并使用getch()
而不是getchar()
是的,您也可以在windows上执行此操作,下面是使用conio.h库的代码
#include <iostream> //basic input/output
#include <conio.h> //provides non standard getch() function
using namespace std;
int main()
{
cout << "Password: ";
string pass;
while(true)
{
char ch = getch();
if(ch=='\r'){ //when a carriage return is found [enter] key
cout << endl << "Your password is: " << pass <<endl;
break;
}
pass+=ch;
cout << "*";
}
getch();
return 0;
}
#包括//基本输入/输出
#include//提供非标准的getch()函数
使用名称空间std;
int main()
{
cout我在目前正在做的作业中遇到了这个问题。
这还取决于您从哪个输入中获取。
我正在使用
/dev/tty
在程序运行时获取输入,因此需要与命令关联的文件流
在ubuntu机器上,我必须测试/瞄准,它需要的不仅仅是
system( "stty -raw" );
或
我必须添加--file标志以及命令的路径,如下所示:
system( "/bin/stty --file=/dev/tty -icanon" );
现在一切都很顺利。我喜欢Lucas answer,但我想详细说明一下。termios.h
中有一个名为cfmakeraw()
的内置函数,man将其描述为:
cfmakeraw() sets the terminal to something like the "raw" mode of the
old Version 7 terminal driver: input is available character by
character, echoing is disabled, and all special processing of
terminal input and output characters is disabled. [...]
这与Lucas的建议基本相同,而且更多,您可以在手册页中看到它设置的确切标志:
用例
这个代码对我有用。注意:这个
/dev/tty
system( "stty -raw" );
system( "stty -icanon" );
system( "/bin/stty --file=/dev/tty -icanon" );
cfmakeraw() sets the terminal to something like the "raw" mode of the
old Version 7 terminal driver: input is available character by
character, echoing is disabled, and all special processing of
terminal input and output characters is disabled. [...]
int c = 0;
static struct termios oldTermios, newTermios;
tcgetattr(STDIN_FILENO, &oldTermios);
newTermios = oldTermios;
cfmakeraw(&newTermios);
tcsetattr(STDIN_FILENO, TCSANOW, &newTermios);
c = getchar();
tcsetattr(STDIN_FILENO, TCSANOW, &oldTermios);
switch (c) {
case 113: // q
printf("\n\n");
exit(0);
break;
case 105: // i
printf("insert\n");
break;
default:
break;
#include <stdio.h>
#include <conio.h>
int main(int argc, char const *argv[]) {
char a = getch();
printf("You typed a char with an ASCII value of %d, printable as '%c'\n", a, a);
return 0;
}
#include <stdio.h>
#include <conio.h>
int main (void)
{
int c;
while ((c = getche()) != EOF)
{
if (c == '\n')
{
break;
}
printf("\n");
}
return 0;
}
#include <stdio.h>
#include <ncurses.h>
int main (void)
{
int c;
cbreak();
echo();
initscr();
while ((c = getch()) != ERR)
{
if (c == '\n')
{
break;
}
printf("\n");
refresh();
}
endwin();
return 0;
}