【问题标题】:Demonstration of noskipws in C++用 C++ 演示 noskipws
【发布时间】:2014-03-15 14:43:02
【问题描述】:

我在 C++ 中试用 noskipws 操纵器,并编写了以下代码。

#include <iostream>
#include <sstream>
#include <string>
using namespace std;

int main()
{
    string first, middle, last;

    istringstream("G B Shaw") >> first >> middle >> last;
    cout << "Default behavior: First Name = " << first << ", Middle Name = " << middle << ", Last Name = " << last << '\n';
    istringstream("G B Shaw") >> noskipws >> first >> middle >> last;
    cout << "noskipws behavior: First Name = " << first << ", Middle Name = " << middle << ", Last Name = " << last << '\n';
}

我希望得到以下输出:

预期输出

Default behavior: First Name = G, Middle Name = B, Last Name = Shaw
noskipws behavior: First Name = G, Middle Name = , Last Name = B

输出

Default behavior: First Name = G, Middle Name = B, Last Name = Shaw
noskipws behavior: First Name = G, Middle Name = , Last Name = Shaw

我修改了这段代码,使其适用于这样的字符,并且运行良好。

#include <iostream>
#include <sstream>
#include <string>
using namespace std;

int main()
{
    char first, middle, last;

    istringstream("G B S") >> first >> middle >> last;
    cout << "Default behavior: First Name = " << first << ", Middle Name = " << middle << ", Last Name = " << last << '\n';
    istringstream("G B S") >> noskipws >> first >> middle >> last;
    cout << "noskipws behavior: First Name = " << first << ", Middle Name = " << middle << ", Last Name = " << last << '\n';
}

我知道 cin 是如何工作的,但我无法弄清楚为什么在 string 的情况下它会以这种方式工作。

【问题讨论】:

    标签: c++ manipulators


    【解决方案1】:
    std::istringstream("G B S") >> std::noskipws >> first >> middle >> last;
    

    当对字符串执行提取时,首先清除字符串并将字符插入到其缓冲区中。

    21.4.8.9 插入器和提取器

     template<class charT, class traits, class Allocator>
     basic_istream<charT, traits>&
         operator>>(basic_istream<charT, traits>& is,
                    basic_string<charT, traits, Allocator>& str);
    

    效果:表现为格式化输入函数 (27.7.2.2.1)。构建哨兵对象后,如果哨兵转换为true调用str.erase(),然后从is中提取字符并将它们附加到str,就像调用str.append(1, c).[。 ..]

    第一次读取会将字符串"G" 提取到first。对于第二次提取,不会提取任何内容,因为设置了 std::noskipws 格式标志,禁用了前导空格的清除。因此,字符串被清除,然后提取失败,因为没有输入任何字符。这是上述子句的延续:

    21.4.8.9 插入器和提取器(续)

    [...] 字符被提取和附加,直到发生以下任何情况:

    • n 字符被存储;

    • 文件结束出现在输入序列上;

    • isspace(c, is.getloc()) 对于下一个可用输入为真 字符c

    当流确定提取失败时,std::ios_base::failbit 设置为流状态,指示错误。

    从此时起,除非流状态被清除,否则任何和所有 I/O 尝试都将失败。提取器无法运行,并且在未清除所有错误的流状态下将无法运行。这意味着提取到last 不会做任何事情,它会保留前一次提取时的值(没有std::noskipws 的那个),因为流没有清除字符串。


    至于使用char 起作用的原因:字符在C 或C++ 中没有格式要求。任何和所有字符都可以提取到 char 类型的对象中,这就是尽管设置了 std::noskipws ,但您仍然看到正确输出的原因:

    27.7.2.2.3/1 [istream::extractors]

    template<class charT, class traits>
    basic_istream<charT, traits>& operator>>(basic_istream<charT, traits>& in,
                                             charT& c);
    

    效果:行为类似于 in 的格式化输入成员(如 27.7.2.2.1 中所述)。构造哨兵对象后,如果有可用的字符,则从 in 中提取一个字符,并将其存储在 c .否则,函数调用in.setstate(failbit)

    提取器的语义会将一个字符存储到其操作数中如果一个可用。它不界定空白(甚至是 EOF 字符!)。它会像普通字符一样提取它。

    【讨论】:

    • 这听起来更合乎逻辑。您能否引用一些参考资料来支持您的回答?
    • @SumitGera 已更新。 :)
    【解决方案2】:

    字符串&gt;&gt;的基本算法是:

    1) 跳过空格
    2)读取并提取直到下一个空格

    如果你使用noskipws,那么first step is skipped

    第一次读取后,您将定位在空白处,因此下一次(以及所有后续)读取将立即停止,不会提取任何内容。
    更多信息可以查看this

    表格cplusplus.com

    许多提取操作将空格本身视为终止字符,因此,在禁用 skipws 标志的情况下,某些提取操作可​​能根本不从流中提取任何字符。
    所以,当使用字符串时,删除 noskipws 。

    【讨论】:

    • 据此,它应该首先读取G,然后因为它会遇到一个空格所以string middle中不会有任何内容,然后B应该保存在string last中但是它将Shaw 保存在string last 中。
    • @mozart:请查看我的编辑并阅读提供的链接,这肯定会解决问题。
    • 好的,我明白了。这意味着string last 根本没有变化?
    【解决方案3】:

    原因是在第二个示例中,您根本没有读取最后一个变量,而是打印它的旧值。

    std::string first, middle, last;
    std::istringstream iss("G B S");
                               ^^^
    iss >> first >> middle >> last;
    std::cout << "Default behavior: First Name = " << first 
                << ", Middle Name = " << middle << ", Last Name = " << last << '\n';
    std::istringstream iss2("G B T");
                                ^^^
    iss2 >> std::noskipws >> first >> middle >> last;
    std::cout << "noskipws behavior: First Name = " << first 
                << ", Middle Name = " << middle << ", Last Name = " << last << '\n';
    

    默认行为:名字 = G,中间名 = B,姓氏 = S

    noskipws 行为:名字 = G,中间名 = ,姓氏 = S

    发生这种情况是因为在第二次读取变量后,最后一个流位于空白处。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-06-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-07
      相关资源
      最近更新 更多