我们在 c 中有一个测试应用程序,它接受使用scanf字符串格式的输入,并使用该字符串进行进一步处理。
到目前为止,一切都工作正常,但是最近我们遇到了需要输入超过 4100 个字节并且scanf需要读取它们的情况,但是scanf从stdin. 有问题的代码的最简单形式如下,
#include <stdio.h>
#include <string.h>
int main()
{
char input_array[5000];
int len;
printf("Enter key: ");
scanf("%s",input_array);
len = strlen(input_array);
printf("Message: %s\n",input_array);
printf("Message Len: %d\n",len);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我认为发生这种情况是因为scanf最多可以读取两行,并且一行大小为 2k。(如果我错了,请纠正我)。
现在,如果我们从文件中读取字符,则此代码可以工作,但这样我们还需要更改其他测试代码:(
目前我们正在终端上复制并粘贴 4200 个字符以向scanf.
现在我的问题是,
有没有办法指示scanf读取超过 2 行?
我们可以使用任何其他没有此限制的函数吗?
这是因为你的终端输入缓冲在内核的I/O 队列中。
终端设备的输入和输出队列在内核中实现一种独立于 I/O 流实现的缓冲的缓冲形式。
终端输入队列有时也称为预输入缓冲区。它保存已从终端接收但尚未被任何进程读取的字符。
输入队列的大小由MAX_INPUT和_POSIX_MAX_INPUT参数描述;
默认情况下,您的终端处于Canonical 模式。
在规范模式下,所有输入都会保留在队列中,直到收到换行符为止,因此当您键入很长的行时,终端输入队列可能会填满。
现在回答您的问题:
有没有办法指示scanf读取超过2行?
2线概念是错误的。scanf无论如何,如果终端 I/O 队列的最大大小设置为 4096 字节,则无法指示读取超过 4096 字节。
我们可以使用任何其他没有此限制的函数吗?
不,你甚至不能使用任何其他功能。这不是 的限制scanf。
编辑:找到了一种相当标准的方法
要更改输入模式,我们必须使用低级终端接口。
我们可以按如下方式完成任务:
#include <stdio.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
int clear_icanon(void)
{
struct termios settings;
int result;
result = tcgetattr (STDIN_FILENO, &settings);
if (result < 0)
{
perror ("error in tcgetattr");
return 0;
}
settings.c_lflag &= ~ICANON;
result = tcsetattr (STDIN_FILENO, TCSANOW, &settings);
if (result < 0)
{
perror ("error in tcsetattr");
return 0;
}
return 1;
}
int main()
{
clear_icanon(); // Changes the input mode of terminal from canonical mode to non canonical mode.
char input_array[5000];
int len;
printf("Enter key: ");
scanf("%s",input_array);
len = strlen(input_array);
printf("Message: %s\n",input_array);
printf("Message Len: %d\n",len);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
如果您想知道如何从终端执行此操作
$ stty -icanon (changes the input mode to non-canonical)
$ stty icanon (changes it back to canonical)
Run Code Online (Sandbox Code Playgroud)
早期的答案是:(这种技术比较旧)
我不知道这是否是最好的方法,但可以通过将终端模式从cooked(默认)更改为cbreak或更改为raw模式来完成。
当终端处于cbreak模式时,它一次处理单个字符,而不是强制等待整行,然后一次性输入该行。
您可以stty cbreak在执行程序之前在终端中使用。
或者
以编程方式使用 cbreak 模式
curses首先通过运行安装包
$ sudo apt-get install libncurses5-dev
Run Code Online (Sandbox Code Playgroud)
接下来编辑程序如下:
#include <stdio.h>
#include <string.h>
#include <curses.h>
int main()
{
initscr(); //start curses mode
cbreak(); //change the terminal mode to cbreak. Can also use raw();
endwin(); //end curses mode
char input_array[5000];
int len;
printf("Enter key:");
scanf("%s",input_array);
len = strlen(input_array);
printf("Message:%s\n",input_array);
printf("Message Len:%d\n",len);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
现在使用-lcurses选项进行编译
$ gcc 1.c -lcurses
Run Code Online (Sandbox Code Playgroud)