【问题标题】:What exactly does stringstream do?stringstream 到底是做什么的?
【发布时间】:2014-01-02 21:01:00
【问题描述】:

我从昨天开始就在尝试学习 C++,我正在使用这个文档:http://www.cplusplus.com/files/tutorial.pdf(第 32 页)。我在文档中找到了一个代码并运行了它。我尝试输入 5.5 卢比的价格和一个整数作为数量,输出为 0。 我试过输入5.5和6,输出是正确的。

// stringstreams
#include <iostream> 
#include <string> 
#include <sstream> 

using namespace std; 

int main () 
{ 
  string mystr; 
  float price = 0; 
  int quantity = 0; 

  cout << "Enter price: "; 
  getline (cin,mystr); 
  stringstream(mystr) >> price; 
  cout << "Enter quantity: "; 
  getline (cin,mystr); 
  stringstream(mystr) >> quantity; 
  cout << "Total price: " << price*quantity << endl; 
  return 0; 
}

mystring 命令究竟做了什么?引用文档:

"在这个例子中,我们从标准输入中获取数值 间接地。而不是直接从 标准输入,我们将标准输入(cin)中的行放入 字符串对象(mystr),然后我们从中提取整数值 将此字符串转换为 int(数量)类型的变量。”

我的印象是该函数将获取字符串的一个组成部分并将其用作输入。

【问题讨论】:

  • 这个例子有点奇怪,我从没见过stringstream这样用过。我通常加载该行,对其进行转换,然后按部分提取,但这显然在这里没有什么优势,因为cin is 已经是一个输入流......所以cin &gt;&gt; price &gt;&gt; quantity; 会简单得多。这将是使用 cplusplus.com 教程的一个很好的理由。
  • 有趣的是,该教程是我第一次接触 C++。事后看来,它非常糟糕和不完整。我建议改为good book
  • @BartekBanachewicz 也许他们只需要拿出示例来展示stringstream 的工作原理。这是一个奇怪的,甚至可能是一个糟糕的 =) 但它表明你可以将字符串视为流。
  • 如果它不是对stringstream 更高级用法的介绍,那么这绝对是一个错误的例子。即使是这样,也应该以不同的方式书写。
  • @trojansdestroy 如果不了解它所基于的所有原语,您将无法理解 stringstream,因此我看不出阅读教程在这方面有何帮助。

标签: c++ sstream


【解决方案1】:

有时使用 stringstream 在字符串和其他数值类型之间进行转换非常方便。 stringstream的用法和iostream的用法差不多,学习起来不是负担。

Stringstreams 可用于读取字符串和将数据写入字符串。它主要与字符串缓冲区一起工作,但没有真正的 I/O 通道。

stringstream类的基本成员函数有

  • str(),它以字符串类型返回其缓冲区的内容。

  • str(string),将缓冲区的内容设置为字符串参数。

这是一个如何使用字符串流的示例。

ostringstream os;
os << "dec: " << 15 << " hex: " << std::hex << 15 << endl;
cout << os.str() << endl;

结果是dec: 15 hex: f

istringstream 的用法大致相同。

总而言之,stringstream 是一种像独立 I/O 设备一样操作字符串的便捷方式。

仅供参考,类之间的继承关系是:

【讨论】:

    【解决方案2】:

    来自C++ Primer

    istringstream类型读取stringostringstream写入stringstringstream 读取和写入 字符串

    我遇到过一些使用 stringstream 既方便又简洁的情况。

    案例一

    来自one of the solutionsthis leetcode problem。它演示了一个非常适合使用 stringstream 高效且简洁的案例。

    假设ab是用字符串格式表示的复数,我们想得到ab的乘法结果也是字符串格式。代码如下:

    string a = "1+2i", b = "1+3i";
    istringstream sa(a), sb(b);
    ostringstream out;
    
    int ra, ia, rb, ib;
    char buff;
    // only read integer values to get the real and imaginary part of 
    // of the original complex number
    sa >> ra >> buff >> ia >> buff;
    sb >> rb >> buff >> ib >> buff;
    
    out << ra*rb-ia*ib << '+' << ra*ib+ia*rb << 'i';
    
    // final result in string format
    string result = out.str() 
    

    案例2

    同样来自leetcode problem,它要求你简化给定的路径字符串,one of the solutions using stringstream是我见过的最优雅的:

    string simplifyPath(string path) {
        string res, tmp;
        vector<string> stk;
        stringstream ss(path);
        while(getline(ss,tmp,'/')) {
            if (tmp == "" or tmp == ".") continue;
            if (tmp == ".." and !stk.empty()) stk.pop_back();
            else if (tmp != "..") stk.push_back(tmp);
        }
        for(auto str : stk) res += "/"+str;
        return res.empty() ? "/" : res; 
     }
    

    不使用stringstream,很难写出这么简洁的代码。

    【讨论】:

      【解决方案3】:

      回答问题。 stringstream 基本上允许您将string 对象视为stream,并在其上使用所有stream 函数和运算符。

      我看到它主要用于格式化输出/输入。

      一个很好的例子是 c++ 实现将数字转换为流对象。

      可能的例子:

      template <class T>
      string num2str(const T& num, unsigned int prec = 12) {
          string ret;
          stringstream ss;
          ios_base::fmtflags ff = ss.flags();
          ff |= ios_base::floatfield;
          ff |= ios_base::fixed;
          ss.flags(ff);
          ss.precision(prec);
          ss << num;
          ret = ss.str();
          return ret;
      };
      

      也许它有点复杂,但它相当复杂。你创建stringstream对象ss,修改它的标志,用operator&lt;&lt;把一个数字放进去,然后通过str()提取它。我猜operator&gt;&gt;可以用。

      同样在本例中,string 缓冲区是隐藏的,没有显式使用。但是写一篇关于所有可能的方面和用例的帖子太长了。

      注意:我可能是从 SO 上的某个人那里偷来的,并加以改进,但我没有注明原作者。

      【讨论】:

      • 注意:ret的使用是不必要的,可以写成return ss.str();
      • @MatthieuM。我想我不确定如果这样写,RVO 是否会启动,或者 ss.str() 返回的对象是否会在退出点存活。这样我就知道我正在制作副本,并且 RVO 可以工作。但你很可能是对的。
      • 其实RVO有2种形式:URVO(未命名,即临时)和NRVO(命名);大多数编译器都实现了 RVO,但有些编译器将其限制为仅 URVO(取决于构建选项)。不过,总的来说,还有很多其他因素需要考虑,因此您应该尽可能编写最简洁的代码,而不必太担心 RVO 是否会启动。
      • NRVO 很常见(与 URVO 一样),但由于移动构造函数,这不是问题。
      【解决方案4】:

      您输入了一个字母数字和整数,在 mystr 中以空格分隔。

      然后您尝试将第一个标记(空格分隔)转换为int

      第一个令牌是 RS,它未能转换为 int,给 myprice 留下一个零,我们都知道零乘以任何东西的结果。

      当您第二次只输入 int 值时,一切都按预期工作。

      是虚假的 RS 导致您的代码失败。

      【讨论】:

        猜你喜欢
        • 2015-08-06
        • 2013-09-02
        • 2013-10-10
        • 2017-05-08
        • 2022-01-20
        • 2012-10-17
        • 2017-06-15
        • 2011-05-20
        • 2010-11-13
        相关资源
        最近更新 更多