如何避免按下input任何getchar()

这是C编程语言的“novato”问题:

在下一个代码中:

#include<stdio.h> int main(void){ int c; while((c=getchar())!= EOF) putchar(c); return 0; } 

我必须按Enter键打印所有使用getcharinput的字母,但是我不想这样做,我想要做的就是按下该字母,然后立即看到我重复引入的字母,而不按Enter键 。 例如,如果我按下字母“a”,我想在旁边看到另一个“a”,依此类推:

 aabbccddeeff..... 

但是当我按下“a”时什么都没有发生,我可以写其他字母,只有当我按下回车键时才会出现副本:

 abcdef abcdef 

我该怎么做?

我在Ubuntu下使用命令cc -o example example.c进行编译。

在Linux系统上,您可以使用stty命令修改terminal行为。 默认情况下,terminal将缓冲所有信息,直到按下Enter键,然后才将其发送到C程序。

一个快速,肮脏,而不是特别便携的例子来改变程序本身的行为:

 #include<stdio.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; } 

请注意,这并不是最佳select,因为它只是假定stty cooked是程序退出时的行为,而不是检查原始terminal设置是什么。 此外,由于所有特殊处理都在原始模式下被跳过,因此许多按键序列(如CTRL-CCTRL-D )实际上并不像您预期​​的那样在程序中明确处理它们。

你可以控制terminal的行为,完全取决于你想达到什么目的。

这取决于您的操作系统,如果您处于类似UNIX的环境中,默认情况下启用ICANON标志,所以input被缓冲直到下一个'\ n'或EOF。 通过禁用规范模式,您将立即得到字符。 这在其他平台上也是可行的,但是没有直接的跨平台解决scheme。

编辑:我看到你指定你使用Ubuntu。 我刚刚发布了类似的东西,但请注意,这将会禁用您的terminal的许多默认行为。

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

你会注意到,每个人物出现两次。 这是因为input立即回显到terminal,然后您的程序也将putchar()放回到terminal。 如果你想从输出中分离input,你还必须打开ECHO标志。 您可以通过简单地将相应的行更改为:

 newt.c_lflag &= ~(ICANON | ECHO); 

getchar()是一个标准函数,在许多平台上,您需要按ENTER才能获得input,因为平台将缓冲input,直到按下该键。 许多编译器/平台都支持不关心input的非标准getch()(绕过平台缓冲,像另一个键那样对待ENTER)。

I / O是一个操作系统function。 在许多情况下,操作系统不会将键入的字符传递给程序,直到按下ENTER键。 这允许用户在将其发送到程序之前修改input(例如退格和重新input)。 对于大多数用途而言,这样做效果很好,为用户提供了一致的界面,并且使程序不必处理这个问题。 在某些情况下,程序从按键中获取字符是可取的。

C库本身处理文件,而不关心数据如何进入input文件。 因此,语言本身没有办法让键被按下; 相反,这是平台特定的。 由于您没有指定操作系统或编译器,我们无法为您查找。

而且,标准输出通常被缓冲以提高效率。 这是由C库完成的,所以有一个C的解决scheme,它是fflush(stdout); 写完每个字符后。 之后,是否立即显示字符取决于操作系统,但所有我熟悉的操作系统将立即显示输出,所以这通常不是问题。

由于您正在使用Unix衍生工具(Ubuntu),所以这里有一个方法可以实现 – 不推荐,但是它可以工作(只要您可以准确input命令):

 echo "stty -g $(stty -g)" > restore-sanity stty cbreak ./your_program 

无聊的时候使用中断来停止程序。

 sh restore-sanity 
  • “回声”行将当前terminal设置保存为一个shell脚本,将恢复它们。
  • “stty”行closures大部分特殊处理(例如, Control-D不起作用),并在程序可用时立即向程序发送字符。 这意味着你不能再编辑你的input。
  • “sh”行恢复原来的terminal设置。

您可以节省“stty sane”是否足够准确地为您的目的恢复您的设置。 '-g'的格式在“stty”版本之间是不可移植的(因此,在Solaris 10上生成的内容在Linux上将不起作用,反之亦然),但是这个概念在任何地方都可行。 “stty理智”选项并不普及,AFAIK(但在Linux上)。

是的,你也可以在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; } 

我喜欢卢卡斯的回答,但我想详细说明一下。 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. [...] 

这基本上和Lucasbuild议的一样,你可以在手册页中看到确切的标志: termios(3) 。

用例

 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; 

默认情况下,C库将缓冲输出直到看到返回。 要立即打印结果,请使用fflush

 while((c=getchar())!= EOF) { putchar(c); fflush(stdout); } 

您可以包含'ncurses'库,并使用getch()而不是getchar()

我有一个问题出现在我正在进行的任务中。 这也取决于你从哪个input中获取。 我在用

 /dev/tty 

在程序运行时得到input,所以需要成为与该命令关联的文件stream。

在Ubuntu的机器上,我必须testing/目标,它需要的不仅仅是

 system( "stty -raw" ); 

要么

 system( "stty -icanon" ); 

我不得不添加–file标志,以及命令的path,如下所示:

 system( "/bin/stty --file=/dev/tty -icanon" ); 

现在一切都是协同的。