c++ noskipws on char extraction from StringStream导致它无法处理后续的字符串提取

vi4fp9gy  于 2023-08-09  发布在  其他
关注(0)|答案(2)|浏览(105)

让我把事情简单化。为什么下面的程序写的是“Thi”而不是“Thisisatest”?我期望它在第一个循环中写入前两个字符,然后写入测试字符串的其余部分,不带空格。

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

int main() {
  string test = "This is just a test.";
  stringstream ss(test);
  
  char c;
  int i = 0;
  while (ss >> noskipws >> c) { 
    int ascii = (int)c;
    if (i > 2) { // break after writing 2 characters
      break;
    }
    i++;
    cout << c; 
  }

  // continue using the same sstring, 
  // but with a string instead of a char
  // notice that there is no noskipws here
  string s;
  while(ss >> s) {
    cout << s; 
  }

  // program exits with only "Thi" printed
  return 0;
}

字符串
有趣的是,删除>> noskipws解决了这个问题。为什么呢?

zysjyyx4

zysjyyx41#

ss >> s表示读入字符串s,遇到空格时停止。
我在程序中添加了一对额外的输出语句,每个循环的末尾都有一个。在第一个循环结束后,输入流被定位为输入空格作为其下一个字符。
当程序尝试输入字符串s时,它会立即遇到空格,并且由于您将流配置为不跳过前导空格,因此它会停止,无法输入字符串s。该失败导致流进入失败状态。

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

int main() {
    string test = "This is just a test.";
    stringstream ss(test);

    char c;
    int i = 0;
    while (ss >> noskipws >> c) {
        int ascii = (int)c;
        if (i > 2) { // break after writing 2 characters
            break;
        }
        i++;
        cout << c;
    }
    std::cout << boolalpha 
        << "\nAfter first loop: " 
        << "\n  ss.fail() : " << ss.fail() 
        << "\n  c         : \'" << c << '\''
        << "\n";

    // continue using the same sstring, 
    // but with a string instead of a char
    // notice that there is no noskipws here
    string s{ "value before ss >> s" };
    while (ss >> s) {
        cout << s;
    }
    std::cout << "\nAfter second loop: "
        << "\n  ss.fail() : " << ss.fail()
        << "\n  s         : \"" << s << '\"'
        << '\n';

    // program exits with only "Thi" printed
    return 0;
}

字符串
输出如下:

Thi
After first loop:
  ss.fail() : false
  c         : 's'

After second loop:
  ss.fail() : true
  s         : ""

ccrfmcuu

ccrfmcuu2#

缩减后的代码(第一个循环读取4个字符,在打印第4个字符之前退出):

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

int main() {
  string test = " is just a test.";
  stringstream ss(test);
  ss >> noskipws;
  
  string s;
  while(ss >> s) {
    cout << s; 
  }
  cout << ss.fail();
}
// Output: 1.

字符串
提取到字符串有a contract
将提取并追加字符,直到出现以下任一情况:

  • 文件结束发生在输入序列上;
  • isspace(c, is.getloc())对于下一个可用的输入字符c为真。

如果没有字符被提取,则std::ios::failbit被设置在流上。
ss >> s作业是str.erase(),然后str.append(1, c)用于上面的每个读取cisspace(c, is.getloc())在第一个字符上为true-不提取任何内容,s为空,流ss被设置为失败状态。

相关问题