昊虹AI笔记网

 找回密码
 立即注册
搜索
查看: 1026|回复: 0
收起左侧

详解C++标准库<sstream>中的类stringstream

[复制链接]

249

主题

252

帖子

976

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
976
昊虹君 发表于 2022-10-28 11:50 | 显示全部楼层 |阅读模式
详解C++标准库<sstream>中的类stringstream

目录
  • 一、字符串格式化函数sprintf()存在的问题
  • 二、详细介绍C++标准库中的类stringstream

一、字符串格式化函数sprintf()存在的问题
在实际工作中,我们常常需要将数值型数据转化为字符串型数据。

此时,您当然可以选择C标准库<stdio.h>中的字符串格式化函数sprintf()来解决这个问题。
在我的博文https://www.hhai.cc/thread-99-1-1.html 的第二个示例代码中便使用了sprintf()将数值转化成字符。

但是函数sprintf()存在一些问题:
①假设你想使用sprintf()函数将一个变量从int类型转换到字符串类型。为了正确地完成这个任务,你必须确保证目标缓冲区有足够大空间以容纳转换完的字符串。假设你要得到的字符串字节数范围为1~100,那你必须保证你为sprintf()函数定义的目标缓冲区有100字节的大小。比如下面这个例子。
  1. int x;
  2. int y;
  3. char temp[16];
  4. sprintf(temp, "(%d,%d)", x, y);
复制代码

上面的代码是没有问题的,但是下面的代码就有问题了:
  1. int x;
  2. int y;
  3. char temp[16];
  4. sprintf(temp, "My current coordinate value is (%d,%d)", x, y);
复制代码

为什么有问题,因为字符串"My current coordinate value is (%d,%d)"是33个字节,超过了字符数组temp的长度16,所以程序运行时就会报错了。

从这个例子我们就会想,如果在转换时能根据任务需要自动分配存储空间那不是更好吗
这是函数sprintf()存在的第一个问题。

②使用sprintf()函数时必须使用正确的格式化符。如果使用了不正确的格式化符,会导致非预知的后果,比如下面这个例子。
  1. int n=10000;
  2. chars[10];
  3. sprintf(s,”%d”,n);// s中的内容为“10000”
复制代码

上面这个代码是没有问题的,但是对上面代码的一个微小的改变就会使程序崩溃,比如下面这样:
  1. int n=10000;
  2. char s[10];
  3. sprintf(s,”%f”,n);// 错误的格式化符
复制代码

从这个例子我们就会想,sprintf()函数在转换时要是能自动推导出正确的类型,那不是更好吗?
这是函数sprintf()存在的第二个问题。


二、详细介绍C++标准库中的类stringstream
C++标准库中的提供了比ANSI C的<stdio.h>更高级的一些功能,即单纯性、类型安全和可扩展性。
库定义了三种类:istringstream、ostringstream和stringstream,分别用来进行流的输入、输出和输入输出操作。

我们常用的是类stringstream,毕竟每个转换都要涉及到输入和输出操作,所以我的这篇博文重点介绍类stringstream的使用。

类stringstream很好地解决了函数sprintf()存在的两个问题。

类stringstream的使用其实很简单,一个简单的示例代码如下:
  1. //该代码实现整型数据转化为字符串
  2. #include <sstream>
  3. #include <iostream>

  4. using namespace std;

  5. int main()
  6. {
  7.         int n = 12345;
  8.         stringstream ss;
  9.         string str;
  10.         ss << n;
  11.         ss >> str;

  12.         cout <<str<< endl<< endl;
  13. }
复制代码

上面的代码运行结果如下:


注意:经过上面代码的处理,输出的12345并不是整型数值12345,而是字符串12345。

类stringstream之所以能解决上面函数sprintf()遇到的两个问题:
一是因为当流传入和传出stringstream对象时(比如上面代码中的“ss << n”和“ss >> str”),它能自动识别推导格式,而不用用户再去手动设置。
二是因为使用string对象来代替字符数组(对应上面的代码“string str;”),它能自动去分配相应的存储空间,这样可以避免流输出时缓冲区溢出的危险(对应上面的代码 “ss >> str”)。

正是因为类stringstream能自动识别推导格式,所以使得它不仅能实现数值类型转化为字符串,也能实现其它类型间的相互转换
上面的代码实现了整型转换为字符串,我们还可以利用它实现字符串转换为浮点型,比如下面的代码。
  1. //该代码实现字符串型数据转化为浮点型数据
  2. #include <sstream>
  3. #include <iostream>

  4. using namespace std;

  5. int main()
  6. {
  7.         string my_string="10000";
  8.         float f_1=0;
  9.         stringstream ss;
  10.         string str;
  11.         ss << my_string;
  12.         ss >> f_1;

  13.         cout <<f_1<< endl<< endl;

  14. }
复制代码

代码运行结果如下:


当然,整型转浮点型也是可以的,比如下面的代码:
  1. //该代码实现整型数据转化为浮点型数据
  2. #include <sstream>
  3. #include <iostream>

  4. using namespace std;

  5. int main()
  6. {
  7.         int n = 1000;
  8.         float f_1=0;
  9.         stringstream ss;
  10.         string str;
  11.         ss << n;
  12.         ss >> f_1;

  13.         cout <<f_1<< endl<< endl;

  14. }
复制代码

运行结果如下:


要注意的是:
stringstream对象的构造和析构函数是比较耗费CPU时间的,所以我们如果要多次进行转换,尽量重复使用同一个stringstream对象。但是在多次转换中使用同一个stringstream对象,要记住再每次转换前要使用clear()方法,否则得不到正确的正果。
比如下面的例子:
[C++] 纯文本查看 复制代码
#include <sstream>
#include <iostream>

using namespace std;

int main()
{
	int n = 1000;
	float f_1=0;
	stringstream ss;
	string str;
	ss << n;
	ss >> f_1;
	cout <<f_1<< endl<< endl;

	//再次使用对象ss进行转换
	string my_string="99999";
	float f_2=0;
	ss << my_string;
	ss >> f_2;
	cout <<f_2<< endl<< endl;

}

上面代码的运行结果如下:

按理,f_2中的值应该是“99999”才对,但从上面的运行结果中我们看到f_2中的值为0,这就是错误的结果。解决方法是在第二次使用stringstream对象前先用方法clear()。下面的代码便能得到正确的结果:
[C++] 纯文本查看 复制代码
#include <sstream>
#include <iostream>

using namespace std;

int main()
{
	int n = 1000;
	float f_1=0;
	stringstream ss;
	string str;
	ss << n;
	ss >> f_1;

	cout <<f_1<< endl<< endl;

	//再次使用对象ss进行转换
	ss.clear(); //再次转换前先clear才能得到正确的结果
	string my_string="99999";
	float f_2=0;
	ss << my_string;
	ss >> f_2;
	cout <<f_2<< endl<< endl;

}

上面的代码的运行结果如下:

从上面的截图中可以看出,经过clear()操作,得到了我们想要的结果。

接下来,我们可利用类stringstream实现OpenCV对图片的批量读取,详情见链接:
https://www.hhai.cc/thread-101-1-1.html

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|昊虹AI笔记网 ( 蜀ICP备2024076726 )

GMT+8, 2024-9-8 13:01 , Processed in 0.023357 second(s), 24 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表