如何避免使用 getchar() 按下 Enter 来仅读取单个字符?
在下一个代码中:
#include <stdio.h>
int main(void) {
int c;
while ((c=getchar())!= EOF)
putchar(c);
return 0;
}
我必须按 Enter 打印我用 getchar
输入的所有字母,但我不想这样做,我想做的是按该字母并立即看到我重复介绍的字母,而无需按 Enter。例如,如果我按字母“a”,我想在它旁边看到另一个“a”,依此类推:
aabbccddeeff.....
但是当我按“a”时什么也没有发生,我可以写其他字母,并且仅当我按“a”时才会出现副本按Enter:
abcdef
abcdef
我该怎么做?
我在Ubuntu下使用命令cc -o example example.c
进行编译。
In the next code:
#include <stdio.h>
int main(void) {
int c;
while ((c=getchar())!= EOF)
putchar(c);
return 0;
}
I have to press Enter to print all the letters I entered with getchar
, but I don't want to do this, what I want to do is to press the letter and immediately see the the letter I introduced repeated without pressing Enter. For example, if I press the letter 'a' I want to see an other 'a' next to it, and so on:
aabbccddeeff.....
But when I press 'a' nothing happens, I can write other letters and the copy appears only when I press Enter:
abcdef
abcdef
How can I do this?
I am using the command cc -o example example.c
under Ubuntu for compiling.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(14)
这取决于您的操作系统,如果您处于类似 UNIX 的环境中,默认情况下会启用 ICANON 标志,因此输入会被缓冲,直到下一个
'\n'
或EOF
。通过禁用规范模式,您将立即获得字符。这在其他平台上也是可能的,但没有直接的跨平台解决方案。编辑:我看到你指定你使用 Ubuntu。我昨天刚刚发布了类似的内容,但请注意,这将禁用终端的许多默认行为。
您会注意到,每个字符出现两次。这是因为输入立即回显到终端,然后您的程序也使用
putchar()
将其放回。如果要取消输入与输出的关联,还必须关闭 ECHO 标志。您只需将相应的行更改为:This depends on your OS, if you are in a UNIX like environment the ICANON flag is enabled by default, so input is buffered until the next
'\n'
orEOF
. By disabling the canonical mode you will get the characters immediately. This is also possible on other platforms, but there is no straight forward cross-platform solution.EDIT: I see you specified that you use Ubuntu. I just posted something similar yesterday, but be aware that this will disable many default behaviors of your terminal.
You will notice, that every character appears twice. This is because the input is immediately echoed back to the terminal and then your program puts it back with
putchar()
too. If you want to disassociate the input from the output, you also have to turn of the ECHO flag. You can do this by simply changing the appropriate line to:在 Linux 系统上,您可以使用 stty 命令修改终端行为。默认情况下,终端将缓冲所有信息,直到按下 Enter,然后再将其发送到 C 程序。
一个快速、肮脏且不是特别便携的示例,用于从程序本身内部更改行为:
请注意,这并不是真正的最佳选择,因为它只是假设 stty Cooked 是程序退出时您想要的行为,而不是检查原始终端设置是什么。此外,由于在原始模式下会跳过所有特殊处理,因此许多按键序列(例如 CTRL-C 或 CTRL-D)实际上不会按您期望的方式工作无需在程序中显式处理它们。
您可以
man stty
对终端行为进行更多控制,具体取决于您想要实现的目标。On a linux system, you can modify terminal behaviour using the
stty
command. By default, the terminal will buffer all information until Enter is pressed, before even sending it to the C program.A quick, dirty, and not-particularly-portable example to change the behaviour from within the program itself:
Please note that this isn't really optimal, since it just sort of assumes that
stty cooked
is the behaviour you want when the program exits, rather than checking what the original terminal settings were. Also, since all special processing is skipped in raw mode, many key sequences (such as CTRL-C or CTRL-D) won't actually work as you expect them to without explicitly processing them in the program.You can
man stty
for more control over the terminal behaviour, depending exactly on what you want to achieve.getchar() 是一个标准函数,在许多平台上要求您按 ENTER 才能获取输入,因为平台会缓冲输入,直到按下该键为止。许多编译器/平台支持不关心 ENTER 的非标准 getch() (绕过平台缓冲,将 ENTER 视为另一个键)。
getchar() is a standard function that on many platforms requires you to press ENTER to get the input, because the platform buffers input until that key is pressed. Many compilers/platforms support the non-standard getch() that does not care about ENTER (bypasses platform buffering, treats ENTER like just another key).
I/O 是操作系统的一项功能。在许多情况下,操作系统不会将键入的字符传递给程序,直到按下 ENTER 键。这允许用户在将输入发送到程序之前修改输入(例如退格和重新键入)。对于大多数用途来说,这种方法效果很好,为用户提供了一致的界面,并使程序不必处理这个问题。在某些情况下,程序需要在按键时从按键中获取字符。
C 库本身处理文件,并不关心数据如何进入输入文件。因此,语言本身无法在按下按键时获取按键;相反,这是特定于平台的。由于您没有指定操作系统或编译器,我们无法为您查找。
此外,为了提高效率,标准输出通常会被缓冲。这是由 C 库完成的,因此有一个 C 解决方案,即在写入每个字符后执行 fflush(stdout); 。之后,是否立即显示字符取决于操作系统,但我熟悉的所有操作系统都会立即显示输出,所以这通常不是问题。
I/O is an operating system function. In many cases, the operating system won't pass typed character to a program until ENTER is pressed. This allows the user to modify the input (such as backspacing and retyping) before sending it to the program. For most purposes, this works well, presents a consistent interface to the user, and relieves the program from having to deal with this. In some cases, it's desirable for a program to get characters from keys as they are pressed.
The C library itself deals with files, and doesn't concern itself with how data gets into the input file. Therefore, there's no way in the language itself to get keys as they are pressed; instead, this is platform-specific. Since you haven't specified OS or compiler, we can't look it up for you.
Also, the standard output is normally buffered for efficiency. This is done by the C libraries, and so there is a C solution, which is to
fflush(stdout);
after each character written. After that, whether the characters are displayed immediately is up to the operating system, but all the OSes I'm familiar with will display the output immediately, so that's not normally a problem.我喜欢卢卡斯的回答,但我想详细说明一下。
termios.h
中有一个名为cfmakeraw()
的内置函数,man 描述为:这基本上与 Lucas 建议的相同更多,您可以在手册页中看到它设置的确切标志: termios (3)。
使用案例
I like Lucas answer, but I would like to elaborate it a bit. There is a built-in function in
termios.h
namedcfmakeraw()
which man describes as:This basically does the same as what Lucas suggested and more, you can see the exact flags it sets in the man pages: termios(3).
Use case
由于您正在开发 Unix 衍生版本(Ubuntu),因此有一种方法可以做到这一点 - 不推荐,但它会起作用(只要您可以准确地键入命令):
当您对程序感到厌倦时,使用中断来停止程序。
如果“stty sane”能够足够准确地恢复您的设置以达到您的目的,您就可以节省开支。 “-g”的格式不可跨版本“stty”移植(因此在 Solaris 10 上生成的内容在 Linux 上不起作用,反之亦然),但该概念在任何地方都适用。 'stty sane' 选项并不是普遍可用的,AFAIK(但在 Linux 上)。
Since you are working on a Unix derivative (Ubuntu), here is one way to do it - not recommended, but it will work (as long as you can type commands accurately):
Use interrupt to stop the program when you are bored with it.
You can economize if 'stty sane' restores your settings sufficiently accurately for your purposes. The format of '-g' is not portable across versions of 'stty' (so what is generated on Solaris 10 won't work on Linux, or vice versa), but the concept works everywhere. The 'stty sane' option is not universally available, AFAIK (but is on Linux).
您可以包含“ncurses”库,并使用
getch()
而不是getchar()
。You could include the 'ncurses' library, and use
getch()
instead ofgetchar()
.首先,终端输入通常是行缓冲或完全缓冲的。这意味着操作系统将来自终端的实际输入存储在缓冲区中。通常,当例如在
stdin
中发出信号/提供\n
时,此缓冲区会刷新到程序。这是通过按 Enter 来完成的。getchar()
位于链的末尾。它没有能力实际影响缓冲过程。首先放弃
getchar()
,如果您不想使用特定的系统调用来明确更改终端的行为,如其他答案中所解释的那样。不幸的是,没有标准库函数,并且没有可移植的方法来在单个字符输入时刷新缓冲区。但是,存在基于实现的解决方案和不可移植的解决方案。
在 Windows/MS-DOS 中,有
getch()
和conio.h
头文件,它完全可以完成您想要的事情 - 读取单个字符,而无需等待换行符刷新缓冲区。getch()
和getche()
是getch()
不会立即在控制台输出实际输入的字符,而getche()
确实如此。附加的“e”
代表echo。示例:
在 Linux 中,获得直接字符处理和输出的一种方法是使用
cbreak ()
和echo()
< /a> 选项和getch()
和 < ncurses-library 中的 href="https://linux.die.net/man/3/refresh" rel="nofollow noreferrer">refresh()
例程。请注意,您需要使用 < 初始化所谓的标准屏幕 code>initscr() 并使用
关闭相同的内容endwin()
例程。示例:
注意:您需要使用
-lncurses
选项调用编译器,以便链接器可以搜索并找到 ncurses-library。First of all, terminal input is commonly either line or fully buffered. This means that the operating system stores the actual input from the terminal in a buffer. Usually, this buffer is flushed to the program when e.g.
\n
was signalized/provided instdin
. This is f.e. made by a press to Enter.getchar()
is just at the end of the chain. It has no ability to actually influence the buffering process.Ditch
getchar()
in the first place, if you don´t want to use specific system calls to change the behavior of the terminal explicitly like well explained in the other answers.There is unfortunately no standard library function and with that no portable way to flush the buffer at single character input. However, there are implementation-based and non-portable solutions.
In Windows/MS-DOS, there are the
getch()
andgetche()
functions in theconio.h
header file, which do exactly the thing you want - read a single character without the need to wait for the newline to flush the buffer.The main difference between
getch()
andgetche()
is thatgetch()
does not immediately output the actual input character in the console, whilegetche()
does. The additional"e"
stands for echo.Example:
In Linux, a way to obtain direct character processing and output is to use the
cbreak()
andecho()
options and thegetch()
andrefresh()
routines in the ncurses-library.Note, that you need to initialize the so called standard screen with the
initscr()
and close the same with theendwin()
routines.Example:
Note: You need to invoke the compiler with the
-lncurses
option, so that the linker can search and find the ncurses-library.是的,你也可以在 Windows 上执行此操作,下面是使用 conio.h 库的代码
yes you can do this on windows too, here's the code below, using the conio.h library
我在当前正在做的作业中遇到了这个问题。
它还取决于您从哪个输入中获取。
我用于
在程序运行时获取输入,因此需要是与命令关联的文件流。
在 ubuntu 机器上,我必须测试/目标,它需要的不仅仅是
或者
我必须添加 --file 标志,以及命令的路径,如下所示:
现在一切都正常了。
I've had this problem/question come up in an assignment that I'm currently working on.
It also depends on which input you are grabbing from.
I am using
to get input while the program is running, so that needs to be the filestream associated with the command.
On the ubuntu machine I have to test/target, it required more than just
or
I had to add the --file flag, as well as path to the command, like so:
Everything is copacetic now.
这段代码对我有用。注意:这不是标准库的一部分,即使大多数编译器(我使用 GCC)都支持它。
此代码检测第一次按键。
This code worked for me. Attention : this is not part of the standard library, even if most compilers (I use GCC) supports it.
This code detects the first key press.
可以创建一个新函数来检查 Enter:
Can create a new function that checks for Enter:
您可以使用 _getch() 而不是中的 getch()
you can use _getch() instead of getch() from <conio.h>
默认情况下,C 库会缓冲输出,直到看到返回为止。要立即打印结果,请使用
fflush
:By default, the C library buffers the output until it sees a return. To print out the results immediately, use
fflush
: