如何正确读取 C 中的标准输入?
How to correctly read stdin in C?
我想用 C 写一个类似 sgtpep/pmenu 的应用程序。
然后我开始看ncurses
库。我的第一次尝试是能够 select 菜单。例如当我做ls | ./a.out
时,它应该能够显示所有文件,并突出显示第一个,当我按UP或DOWN,它会相应地改变突出显示不同的项目。
完整代码为here。
程序没有收到任何按键。 mvprintw(n+1, 0, "%d\n", ch);
在循环内总是打印 -1
.
然后我删除不相关的代码,得到最小的例子。
#include <stdio.h>
char buf[100];
int main(int argc, char **argv) {
int ch;
while (fgets(buf, sizeof(buf), stdin)) puts(buf);
ch = getch();
printf("%d\n", ch);
ch = getch();
printf("%d\n", ch);
ch = getch();
printf("%d\n", ch);
ch = getch();
printf("%d\n", ch);
return 0;
}
ch
总是 -1
。我怀疑 stdin
不干净,所以我在 fgets
之后使用 fflush(stdin)
,但结果相同。
那么 stdin
的正确阅读方式是什么?
UPD1
#include <stdio.h>
char buf[100];
int main(int argc, char **argv) {
int ch;
while (fgets(buf, sizeof(buf), stdin)) puts(buf);
fflush(stdin);
ch = getchar();
printf("%d\n", ch);
ch = getchar();
printf("%d\n", ch);
ch = getchar();
printf("%d\n", ch);
ch = getchar();
printf("%d\n", ch);
return 0;
}
我修改了程序,所以和ncurses
没有关系了,但是当运行ls | ./a.out
时,ch
一直显示-1
。
UPD2
使用 newterm
重定向 in
并且 out
有效。
FILE *fd = fopen("/dev/tty", "r+");
set_term(newterm(NULL, fd, fd)); // instead of initscr()
noecho();
cbreak();
keypad(stdscr, TRUE);
print_menu(cur, n);
while (true) {
ch = getch();
if (ch == KEY_UP || ch == 'k') --cur;
else if (ch == KEY_DOWN || ch == 'j') ++cur;
cur = (cur + n) % n;
print_menu(cur, n);
}
endwin();
如果您要以这种方式从 stdin 切换到 curses,则必须打开终端设备,例如,/dev/tty
当您完成读取标准输入。打开终端后,您可以使用 newterm
(which has parameters for the input/output streams unlike initscr
).
初始化 curses
有关示例,请参阅 ncurses test-program, or dialog。
curses 是标准输入的替代品。
C 模型是用户在控制台中编写一行,这为他提供了行编辑功能。他可以返回 space 并使用箭头键在直线上移动,直到他满意为止。然后他按下回车键,程序得到整行。然后程序会对其进行处理,通常会提示输入下一行。
curses 接管了键盘,因此它可以用作小键盘 - 你可以玩一个 space 入侵者小游戏 "z" 意思是 "left" 和 "x" 意思是 "right"。因此,你不应该同时尝试从 stdin 读取,你会得到字符,但 curses 系统会以奇怪的方式与它们交互。通过诅咒独家阅读。
在你的上一个程序中,你读取了直到 EOF 的输入。因此,后续输入是 EOF。
我想用 C 写一个类似 sgtpep/pmenu 的应用程序。
然后我开始看ncurses
库。我的第一次尝试是能够 select 菜单。例如当我做ls | ./a.out
时,它应该能够显示所有文件,并突出显示第一个,当我按UP或DOWN,它会相应地改变突出显示不同的项目。
完整代码为here。
程序没有收到任何按键。 mvprintw(n+1, 0, "%d\n", ch);
在循环内总是打印 -1
.
然后我删除不相关的代码,得到最小的例子。
#include <stdio.h>
char buf[100];
int main(int argc, char **argv) {
int ch;
while (fgets(buf, sizeof(buf), stdin)) puts(buf);
ch = getch();
printf("%d\n", ch);
ch = getch();
printf("%d\n", ch);
ch = getch();
printf("%d\n", ch);
ch = getch();
printf("%d\n", ch);
return 0;
}
ch
总是 -1
。我怀疑 stdin
不干净,所以我在 fgets
之后使用 fflush(stdin)
,但结果相同。
那么 stdin
的正确阅读方式是什么?
UPD1
#include <stdio.h>
char buf[100];
int main(int argc, char **argv) {
int ch;
while (fgets(buf, sizeof(buf), stdin)) puts(buf);
fflush(stdin);
ch = getchar();
printf("%d\n", ch);
ch = getchar();
printf("%d\n", ch);
ch = getchar();
printf("%d\n", ch);
ch = getchar();
printf("%d\n", ch);
return 0;
}
我修改了程序,所以和ncurses
没有关系了,但是当运行ls | ./a.out
时,ch
一直显示-1
。
UPD2
使用 newterm
重定向 in
并且 out
有效。
FILE *fd = fopen("/dev/tty", "r+");
set_term(newterm(NULL, fd, fd)); // instead of initscr()
noecho();
cbreak();
keypad(stdscr, TRUE);
print_menu(cur, n);
while (true) {
ch = getch();
if (ch == KEY_UP || ch == 'k') --cur;
else if (ch == KEY_DOWN || ch == 'j') ++cur;
cur = (cur + n) % n;
print_menu(cur, n);
}
endwin();
如果您要以这种方式从 stdin 切换到 curses,则必须打开终端设备,例如,/dev/tty
当您完成读取标准输入。打开终端后,您可以使用 newterm
(which has parameters for the input/output streams unlike initscr
).
有关示例,请参阅 ncurses test-program, or dialog。
curses 是标准输入的替代品。
C 模型是用户在控制台中编写一行,这为他提供了行编辑功能。他可以返回 space 并使用箭头键在直线上移动,直到他满意为止。然后他按下回车键,程序得到整行。然后程序会对其进行处理,通常会提示输入下一行。
curses 接管了键盘,因此它可以用作小键盘 - 你可以玩一个 space 入侵者小游戏 "z" 意思是 "left" 和 "x" 意思是 "right"。因此,你不应该同时尝试从 stdin 读取,你会得到字符,但 curses 系统会以奇怪的方式与它们交互。通过诅咒独家阅读。
在你的上一个程序中,你读取了直到 EOF 的输入。因此,后续输入是 EOF。