在C ++中使用带有Width()的cin以避免缓冲区溢出

时间:2012-01-07 01:43:17

标签: c++ file io buffer-overflow

这是一个简单的问题。我写了这个C ++代码:

    char chaine[12];
    cin.width(12);
    cin >> chaine;

但是如果我在运行时输入一些超过12个字符的文本,Visual studio告诉我堆栈现在已损坏。

据我所知,问题是缓冲区溢出。但我认为“宽度”方法可以防止这种情况发生。

有人可以向我解释一下宽度方法的功能是什么,如果它不能防止缓冲区溢出?我在网上搜索但我没有找到任何东西。

谢谢!

1 个答案:

答案 0 :(得分:3)

这段代码确实应该将输入限制为11个字符(第12个字符用于终止空字符)。该标准明确载于27.7.2.2.3 [istream :: extractors]第7和第8段:

  

...如果width()大于零,则n为width()。 ...提取并存储字符,直到出现以下任何一种情况: - 存储n-1个字符; ...

我也尝试过gcc,它只能读取11个字符。我不知道这个问题最好的解决办法是什么。通常情况下,我不会遇到这样的问题,因为我简单地阅读std::string对象,这些对象可以根据需要增长。好吧,还有一些巨大的限制,我从来没有尝试过这会超出的情况。如果您绝对需要阅读char数组,您可以做两件事:

  1. 您可以为char数组创建适配器并自己定义合适的输入运算符
  2. 您可以创建一个临时安装的过滤流缓冲区,该缓冲区限制字符数或假装读取空格字符。
  3. 以下是如何做后者的示例。创建适配器的技术实际上可以用于根据数组的大小自动设置宽度。

    #include <iostream>
    #include <cctype>
    
    struct adaptor
    {
        template <int Size>
        adaptor(char (&array)[Size]): it(array), end(array + Size - 1) {}
        mutable char*  it, * end;
    };
    
    std::istream& operator>> (std::istream& in, adaptor const& value)
    {
        std::istreambuf_iterator<char> it(in), end;
        if (it == end)
        {
            in.setstate(std::ios_base::failbit);
        }
        for (; it != end && value.it != value.end && !std::isspace(static_cast<unsigned char>(*it));
             ++it, ++value.it)
        {
            *value.it = *it;
        }
        *value.it = 0;
        return in;
    }
    
    int main()
    {
        char buffer[12];
        if (std::cin >> adaptor(buffer))
            std::cout << "read='" << buffer << "'\n";
        else
            std::cout << "input failed\n";
    }