在C++中从标准输入读取长度大于4096字节的字符串

8

我正在尝试读取一个长度为10^5的字符串。如果字符串的大小超过4096,我将得到不正确的字符串。 我使用以下代码:

string a;
cin>>a;

这个方法没起作用,然后我尝试使用以下代码逐个读取字符

unsigned char c;
vector<unsigned char> a;
while(count>0){
 c = getchar();
 a.push_back(c);
 count--;
}

我已经对使用getchar做了必要的转义,但仍存在4096字节的问题。有人能提供解决方法或指向正确的读取方式吗?


你使用的是哪个C运行时?看起来很奇怪,cin不能处理“任何大小的字符串” - 但我必须承认我没有尝试过。 - Mats Petersson
3
你是在终端读取吗?终端输入缓冲区容量有限。 - Brian Bi
1
你是在终端中复制粘贴吗?这可能是终端或shell程序的问题。 - Potatoswatter
10^5阶?天啊。这是什么,像“输入你最喜欢的莎士比亚作品并按回车键”吗?开玩笑了,你的stdin是什么?通常是控制台,它通常甚至没有那么大的缓冲区,因此,你无法从中读取那么多内容。 - Kahler
3个回答

6
这是因为你的终端输入被缓存在内核的I/O队列中。

终端设备的输入和输出队列在内核中实现了一种缓冲形式,独立于I/O流实现的缓冲。

终端输入队列有时也称为它的预读缓冲区。它保存从终端接收但尚未被任何进程读取的字符。

输入队列的大小由MAX_INPUT和_POSIX_MAX_INPUT参数描述;

默认情况下,你的终端处于规范模式

在规范模式下,所有输入都保留在队列中,直到接收到换行符,因此当你输入非常长的行时,终端输入队列会填满。


我们可以将终端的输入模式从规范模式更改为非规范模式
您可以通过终端完成此操作:
$ stty -icanon (change the input mode to non-canonical)
$ ./a.out (run your program)
$ stty icanon (change it back to canonical)

或者您也可以通过编程的方式进行更改,

要通过编程方式更改输入模式,我们必须使用低级终端界面

因此,您可以执行以下操作:

#include <iostream>
#include <string>
#include <stdio.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 terminal from canonical mode to non canonical mode.

    std::string a;

    std::cin >> a;

    std::cout << a.length() << std::endl;
}

4

使用你发布的测试程序:

#include <iostream>
#include <string>


int main()
{
    std::string a;

    std::cin >> a;

    std::cout << a.length() << std::endl;
}

我能做到:

./a.out < fact100000.txt

并获得输出:

456574

然而,如果我从编辑器复制粘贴到控制台,它会在4095处停止。我认为这是控制台复制粘贴处理中的某个限制。当然,解决这个问题的简单方法是不使用复制粘贴,而是从文件中重定向输入。在其他一些系统上,对于4KB的输入限制可能存在于其他地方。(请注意,在我的系统上,至少可以愉快地将450KB的结果复制并粘贴到另一个编辑器窗口中,因此在我的系统中只是控制台缓冲区成了问题)。

我会尝试您的解决方案并告诉您。 - Baruntar
考虑到你对另一个答案的评论,以及我也在使用 Fedora(尽管是旧版本的 Fedora 16),很可能你无法在终端输入中键入超过4K的字符。请记住,终端输入是“烹饪”的,换句话说,在实际程序接收之前会进行处理,因此必须限制输入的数量。 - Mats Petersson
Windows / VS 显示 long word 的最大值为 4094,即使有空格并且必须阅读所有单独的 tokens,结果也是类似的。 - Tom

2

这很可能是平台/操作系统的问题,而不是C++的问题。您使用的是什么操作系统,并且使用什么方法将字符串传递给stdin?命令行参数通常会被限制在一定的大小范围内。

特别是,考虑到您已经尝试逐个字符地读取,但仍然没有起作用,这似乎是将字符串传递程序的问题,而不是C ++问题。


我使用的是Linux,Fedora 20 64。我没有使用任何命令行参数。我只是在运行我的可执行文件后,在Bash终端中键入我的输入,没有重定向。这不是字符串问题,因为在代码片段中我使用了向量。我将尝试发布我输入的内容以及在我的字符串和向量中得到的内容。 - Baruntar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接