如何使 scanf 读取超过 4095 个作为输入给出的字符?

Ank*_*ank 4 c linux gcc

我们在 c 中有一个测试应用程序,它接受使用scanf字符串格式的输入,并使用该字符串进行进一步处理。

到目前为止,一切都工作正常,但是最近我们遇到了需要输入超过 4100 个字节并且scanf需要读取它们的情况,但是scanfstdin. 有问题的代码的最简单形式如下,

#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 行?
我们可以使用任何其他没有此限制的函数吗?

Ram*_*man 5

这是因为你的终端输入缓冲在内核的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)