在下一个代码中:
#include <stdio.h>
int main(void) {
int c;
while ((c=getchar())!= EOF)
putchar(c);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我必须按Enter下来打印我输入的所有字母getchar,但我不想这样做,我想要做的就是按下这封信,然后立即看到我重复介绍的信,而不是按下Enter.例如,如果我按下'a'字母,我想在旁边看到另一个'a',依此类推:
aabbccddeeff.....
Run Code Online (Sandbox Code Playgroud)
但当我按'a'时没有任何反应,我可以写其他字母,只有当我按下时才会出现副本Enter:
abcdef
abcdef
Run Code Online (Sandbox Code Playgroud)
我怎样才能做到这一点?
我正在使用cc -o example example.cUbuntu下的命令进行编译.
Luc*_*cas 84
这取决于您的操作系统,如果您在类似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;
}
Run Code Online (Sandbox Code Playgroud)
你会注意到,每个角色出现两次.这是因为输入会立即回显给终端,然后您的程序putchar()也会将其返回.如果要取消输出与输出的关联,还必须转动ECHO标志.您只需将相应的行更改为:
newt.c_lflag &= ~(ICANON | ECHO);
Run Code Online (Sandbox Code Playgroud)
gol*_*udo 65
在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;
}
Run Code Online (Sandbox Code Playgroud)
请注意,这不是最佳选择,因为它只是假设这stty cooked是程序退出时所需的行为,而不是检查原始终端设置是什么.此外,由于在原始模式下跳过所有特殊处理,因此许多键序列(例如CTRL-C或CTRL-D)实际上不会像您期望的那样工作,而无需在程序中显式处理它们.
您可以man stty更好地控制终端行为,具体取决于您希望实现的目标.
getchar()是一个标准函数,在许多平台上都要求你按ENTER键来获取输入,因为平台缓冲输入直到按下该键.许多编译器/平台支持不关心ENTER的非标准getch()(绕过平台缓冲,将ENTER视为另一个键).
I/O是一个操作系统功能.在许多情况下,在按下ENTER之前,操作系统不会将键入的字符传递给程序.这允许用户在将输入发送到程序之前修改输入(例如退格和重新输入).在大多数情况下,这种方法效果很好,为用户提供了一致的界面,并使程序无需处理此问题.在某些情况下,程序需要在按下时从键中获取字符.
C库本身处理文件,并不关心数据如何进入输入文件.因此,语言本身无法在按下键时获取键; 相反,这是特定于平台的.由于您尚未指定操作系统或编译器,因此我们无法为您查找.
此外,标准输出通常是缓冲的,以提高效率.这是由C库完成的,因此有一个C解决方案,即fflush(stdout);在每个字符写入之后.之后,是否立即显示字符取决于操作系统,但我熟悉的所有操作系统都会立即显示输出,因此通常不会出现问题.
由于您正在开发 Unix 衍生版本(Ubuntu),因此这里有一种方法 - 不推荐,但它会起作用(只要您可以准确地键入命令):
echo "stty -g $(stty -g)" > restore-sanity
stty cbreak
./your_program
Run Code Online (Sandbox Code Playgroud)
当你对程序感到厌烦时,使用中断来停止它。
sh restore-sanity
Run Code Online (Sandbox Code Playgroud)
如果“stty sane”能够足够准确地恢复您的设置以达到您的目的,您就可以节省开支。“-g”的格式不可跨版本“stty”移植(因此在 Solaris 10 上生成的内容在 Linux 上不起作用,反之亦然),但该概念在任何地方都适用。'stty sane' 选项并不是普遍可用的,AFAIK(但在 Linux 上)。
小智 5
我喜欢卢卡斯的回答,但我想对其进行详细说明。在termios.hnamed中有一个内置函数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. [...]
Run Code Online (Sandbox Code Playgroud)
这基本上与Lucas建议的功能相同,并且更多,您可以在手册页中看到它设置的确切标志: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;
Run Code Online (Sandbox Code Playgroud)