string和stringstream用法_stringstream和string的区别-程序员宅基地

技术标签: C/C++  语言  c++  c  string  编程初学者  

一、string

string 是 C++ 提供的字符串类型,和 C 的字串相比,除了有不限长度的优点外,还有其他许多方便的功能。要使用 string, 必须先加入这一行:

#include <string>

接下來要定义一个字串变量,可以写成:

string s;

我们也可以在定义的同时初始化字串:

string s = "you";

而要取得其中某一个字元,和传统C 的字串一样是用 s[i] 的方式取得。比较不一样的是如果 s 有三个字元,传統 C 的字串的 s[3] 是'\0' 字符,但是 C++ 的 string 则是只到 s[2] 这个字符而已。


做一个对照:

操作 string 字符数组
定义字符串
string s; char s[100];
取得第i个字符 s[i] s[i]
字符串长度 s.length()
或 s.size()
strlen(s)
读入一行 getline(cin, s); gets(s);
赋值 s = "you"; strcpy(s, "you");
字符串连接 s = s + "you";
s += "you";
strcat(s, "you");
字符串比较 s == "you" strcmp(s, "you");


两个string常用的方法是find和substr。在下面的代码当中:find函数从str的第3个位置查起,找到ssdf这个子串后,返回子串的位置。而substr函数从pos位置开始,截取5个字符,赋值给str2。也就是说,str2之后的内容将是ssdfs。

string str = "aaaaddddssdfsasdf";  
size_t pos = str.find("ssdf", 3);
//可以用if(pos == string::npos) 用来判断是否找到子串。
//传送门: http://blog.csdn.net/sunshineacm/article/details/78075135 
string str2 = str.substr(pos, 5);


二、stringstream

stringstream是 C++ 提供的另一个字串型的串流(stream)物件,和之前学过的iostreamfstream有类似的操作方式。要使用stringstream, 必须先加入这一行:

#include <sstream>

stringstream主要是用在將一个字符串分割,可以先用.clear( )以及.str( )將指定字串设定成一开始的內容,再用>>把个別的资料输出。


举个例子:

題目:输入的第一行有一个数字 N 代表接下來有 N 行资料,每一行资料里有不固定个数的整数(最多20个,每行最大200个字元),编程將每行的总和打印出來。

输入:

3
1 2 3
20 17 23 54 77 60
111 222 333 444 555 666 777 888 999

输出:

6
251
4995


代码:

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

int main()
{
    string s;
    stringstream ss;
    int n;

    cin >> n;
    getline(cin, s);  //读取换行
    for (int i = 0; i < n; i++)
    {
        getline(cin, s);
        ss.clear();
        ss.str(s);

        int sum = 0;

        while (1)
        {
            int a;

            ss >> a;
            if(ss.fail())
                break;
            sum += a;
        }
        cout << sum << endl;
    }

    return 0;
}

三、使用stringstream简化类型转换

C++标准库中的<sstream>提供了比ANSI C的<stdio.h>更高级的一些功能,即单纯性、类型安全和可扩展性。接下来,我将举例说明怎样使用这些库来实现安全和自动的类型转换。

一个例子:

#include <stdio.h>

int main()
{
	int n = 10000;
    char s[10];

    sprintf(s, "%d", n);
    //s中的内容为“10000”
	//到目前为止看起来还不错。但是,对上面代码的一个微小的改变就会使程序发生错误
	printf("%s\n", s);

    sprintf(s, "%f", n);
    //错误的格式化符
    printf("%s\n", s);

    return 0;
}
输出:


在这种情况下,由于错误地使用了 %f 格式化符来替代了%d。因此,s在调用完sprintf()后包含了一个不确定的字符串。要是能自动推导出正确的类型,那不是更好吗?

进入stringstream:

由于ns的类型在编译期就确定了,所以编译器拥有足够的信息来判断需要哪些转换。<sstream>库中声明的标准类就利用了这一点,自动选择所必需的转换。而且,转换结果保存在stringstream对象的内部缓冲中。你不必担心缓冲区溢出,因为这些对象会根据需要自动分配存储空间。

<sstream>库定义了三种类:istringstream、ostringstream和stringstream,分别用来进行流的输入、输出和输入输出操作。另外,每个类都有一个对应的宽字符集版本。简单起见,我主要以stringstream为中心,因为每个转换都要涉及到输入和输出操作。

注意,<sstream>使用string对象来代替字符数组。这样可以避免缓冲区溢出的危险。而且,传入参数和目标对象的类型被自动推导出来,即使使用了不正确的格式化符也没有危险。

1、string到int的转换

string result = "10000";  
int n = 0;  
stream << result;  
stream >> n;  //n等于10000 


2.重复利用stringstream对象

如果你打算在多次转换中使用同一个stringstream对象,记住在每次转换前要使用clear()方法。

在多次转换中重复使用同一个stringstream(而不是每次都创建一个新的对象)对象最大的好处在于效率。stringstream对象的构造和析构函数通常是非常耗费CPU时间的。


3.在类型转换中使用模板

你可以轻松地定义函数模板来将一个任意的类型转换到特定的目标类型。例如,需要将各种数字值,如int、long、double等等转换成字符串,要使用以一个string类型和一个任意值t为参数的to_string()函数。to_string()函数将t转换为字符串并写入result中。使用str()成员函数来获取流内部缓冲的一份拷贝。

template<class T>  
  
void to_string(string &result, const T &t)  
{  
  
	ostringstream oss;  //创建一个流  
	oss << t;  //把值传递入流中  
	result = oss.str();  //获取转换后的字符并将其写入result  
}  

//这样,你就可以轻松地将多种数值转换成字符串了    
to_string(s1, 10.5);  //double到string  
to_string(s2, 123);  //int到string  
to_string(s3, true);  //bool到string  
  
  
  
  
//可以更进一步定义一个通用的转换模板,用于任意类型之间的转换。函数模板convert()含有两个模板参数out_type和in_value,功能是将in_value值转换成out_type类型:  
  
template<class out_type, class in_value>  
  
out_type convert(const in_value & t)  
{  
	stringstream stream;  
  
	stream << t;  //向流中传值  
	out_type result;  //这里存储转换结果  
	stream >> result;  //向result中写入值  
  
	return result;  
}  

测试代码:

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

template<class T>
void to_string(string &result, const T &t)
{

	ostringstream oss;
	oss << t;
	result = oss.str();
}

template<class out_type, class in_value>
out_type convert(const in_value & t)
{
	stringstream stream;

	stream << t;
	out_type result;
	stream >> result;

	return result;
}

int main()
{
	//to_string实例
	string s1, s2, s3;

	to_string(s1, 10.5);  //double到string
	to_string(s2, 123);  //int到string
	to_string(s3, true);  //bool到string
	cout << s1 << endl << s2 << endl << s3 << endl << endl;

	//convert()例子
	double d;
	string salary;
	string s = "12.56";

	d = convert <double> (s);  //d等于12.56
	salary = convert <string> (9000.0); //salary等于"9000"

	cout << d << endl << salary << endl;

	return 0;
}
输出:



4.结论

在过去留下来的程序代码和纯粹的C程序中,传统的<stdio.h>形式的转换伴随了我们很长的一段时间。但是,如文中所述,基于stringstream的转换拥有类型安全和不会溢出这样的特性,使我们有充足得理由去使用<sstream>。<sstream>库还提供了另外一个特性—可扩展性。你可以通过重载来支持自定义类型间的转换。


5.一些实例

stringstream通常是用来做数据转换的。相比c库的转换,它更加安全,自动和直接。

例子一: 基本数据类型转换例子 int 转 string

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

int main()
{
	stringstream ss;
	string s;
	int i = 1000;

	ss << i;
	ss >> s;
	cout << s << endl;

	return 0;
}

运行结果:



例子二: 除了基本类型的转换,也支持char *的转换

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

int main()
{
	stringstream ss;
	char s[10];

	ss << 8888;
	ss >> s;
	cout << s << endl;

	return 0;
}

运行结果:



例子三: 再进行多次转换的时候,必须调用stringstream的成员函数.clear()

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

int main()
{
	stringstream ss;
	int first = 0, second = 0;

	ss << "456";  // 插入字符串
	ss >> first;  //转换成int
	cout << first << endl;

	ss.clear();  //在进行多次转换前, 必须清除ss
	ss << true;
	ss >> second;
	cout << second << endl;

	return 0;
}

运行结果:

运行.clear()结果


没有运行.clear()结果



6.使用误区

如果stringstream使用不当,当心内存出问题。试试下面的代码,运行程序前打开任务管理器,看看内存变化。

复制代码,把 stream.str("");  那一行的注释去掉,再运行程序,内存就正常了。


看来stringstream似乎不打算主动释放内存( 或许是为了提高效率 ),但如果你要在程序中用同一个流,反复读写大量的数据,将会造成大量的内存消耗,因此这时候,需要适时地清除一下缓冲 ( 用 stream.str("")  )。

另外不要企图用  stream.str().resize(0) 或  stream.str().clear()  来清除缓冲,使用它们似乎可以让stringstream的内存消耗不要增长得那么快,但仍然不能达到清除stringstream缓冲的效果(做个实验就知道了,内存的消耗还在缓慢的增长)

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

int main()
{
	std::stringstream stream;
	string str;

	while(1)
	{
		//clear()这个名字让很多人想当然地认为它会清除流的内容。
		//实际上它并不清空任何内容,它只是重置了流的状态标志。
		stream.clear();
		//去掉下面这行注释,清空stringstream的缓冲,每次循环内存消耗将不再增加。
		//stream.str("");
		stream << "you see see you";
		stream >> str;
		// 去掉下面这行注释,看看每次循环,你的内存消耗会增加多少
		//cout << "Size of stream = " << stream.str().length() << endl;
	}

	return 0;
}

参考链接:

http://blog.csdn.net/zhang_xueping/article/details/47846807

http://blog.csdn.net/u014097230/article/details/52089530


版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/sunshineacm/article/details/78068987

智能推荐

EBS R12基本概念与应用基础-程序员宅基地

文章浏览阅读1.8k次。摘自: [ORACLE EBS 入门及供应链核心系统详解教程] (书籍)EBS基础功能架构(13个核心模块,业财一体化)业务运营管理,价值增值财务会计管理,价值实现应用架构Finance财务,资金流Accounting财务管理Bisuness业务,实物流核心业务,与财务高度集成;PUR、INV、制造、订单履行等间接业务,or专业业务,为核心业务提供支持;HR..._ebs r12

Java中Date和Timestamp的区别_java date timestamp区别-程序员宅基地

文章浏览阅读838次。转载:https://blog.csdn.net/ccecwg/article/details/39546307_java date timestamp区别

如何用原生js封装一个类似jq的选择器_原声js实现jq元素选择器-程序员宅基地

文章浏览阅读1.4k次。1、我们先了解一下原生js中的选择器ID选择器(在整个文档中获取id为xxx的元素)document.getElementId([ID]);类名选择器(在整个文档中或者在指定上下文中获取类名为xxx的元素)document.getElementsByClassName(' ');[context].getElementsByClassName(' ');标签名选择器(在整个文档中或者..._原声js实现jq元素选择器

Hive中partition by和distribute by区别_partition by distribute by-程序员宅基地

文章浏览阅读1.2k次,点赞3次,收藏4次。通常查询时会对整个数据库查询,而这带来了大量的开销,因此引入了partition的概念,在建表的时候通过设置partition的字段, 会根据该字段对数据分区存放,更具体的说是存放在不同的文件夹,这样通过指定设置Partition的字段条件查询时可以减少大量的开销。1)partition by [key..] order by [key..]只能在窗口函数中使用,而distribute by [key...] sort by [key...]在窗口函数和select中都可以使用。_partition by distribute by

游标(cursor )是什么?_c# cursor-程序员宅基地

文章浏览阅读7.3k次。Private SQL Area A private SQL area holds information about a parsed SQLstatement and other session-specific information for processing. When a serverprocess executes SQL or PL/SQL code, the process_c# cursor

listview使用的一些心得_listview的使用——购物商城实验心得-程序员宅基地

文章浏览阅读616次。近日在用ListView中的一些注意点,和公用代码,整理如下1.ListView.Items.Clear而不是ListView.Clear一般如果ListView是动态填充的,我们在填充之前都会先进行清理。但需要注意一下,我们是清理Items,如果去直接Clear整个ListView,就连原先定义好的列都没有了2.给ListView绑定数据ListView并不能直接_listview的使用——购物商城实验心得

随便推点

java 注解处理器的作用_深入理解Java:注解(Annotation)--注解处理器-程序员宅基地

文章浏览阅读110次。如果没有用来读取注解的方法和工作,那么注解也就不会比注释更有用处了。使用注解的过程中,很重要的一部分就是创建于使用注解处理器。Java SE5扩展了反射机制的API,以帮助程序员快速的构造自定义注解处理器。注解处理器类库(java.lang.reflect.AnnotatedElement):Java使用Annotation接口来代表程序元素前面的注解,该接口是所有Annotation类型的父接口..._java注解处理器作用

全国职业技能大赛高职组(最新职业院校技能大赛_大数据应用开发2023国赛样题解析-模块C:实时数据处理-任务二:实时指标计算)_大数据 国赛 样题-程序员宅基地

文章浏览阅读1.8k次,点赞27次,收藏28次。全国职业技能大赛高职组(最新职业院校技能大赛_大数据应用开发样题解析-模块B:数据采集-任务一:离线数据采集-程序员宅基地。_大数据 国赛 样题

ssm+mysql+微信小程序疫情防控小程序-计算机毕业设计源码73691_ssm+微信小程序-程序员宅基地

文章浏览阅读926次。本系统分为管理员和注册用户两个角色,主要有疫情新闻、疫情案例介绍、健康信息申报、行程信息申报、就医流程介绍、举报、在线留言、用户管理、信息统计等模块。用户需要先注册成为会员,成功登录后,可以查看网站发布的疫情新闻,可以查看疫情相关病例介绍,有助于疫情防范,还可以查看网站发布的重大疫情案例,了解疫情的发展状况,出行时候好做好防护,同时通过网站可以上报健康信息,以及上报行程信息,方便社区了解自己的出行情况;网站还发布了疫情状态下的就医流程,方便大家就医时候做好准备;同时网站还提供了举报功能,如果发现外来人员或_ssm+微信小程序

Linux 操作系统 022-串口/U盘/共享文件夹-程序员宅基地

文章浏览阅读296次,点赞3次,收藏9次。本节关键字:Linux、centos、串口、U盘、共享文件夹本节相关指令:echo、cat、mkdir、mount

解密C++新特性:内联函数、auto和基于范围的for循环-程序员宅基地

文章浏览阅读1.3k次,点赞45次,收藏29次。本篇主题为: 解密C++新特性:内联函数、auto关键字和基于范围的for循环。

上岸整理:2023前端面试题-vue,小程序,js,css_今年的前端面试难不难-程序员宅基地

文章浏览阅读774次,点赞4次,收藏11次。1、浏览器常见的报错信息与含义2、304与204的区别,http缓存,强缓存,协商缓存3、浏览器从输入地址到渲染,经历了什么状态?4、vue的界面渲染,经过哪些过程(生命周期)5、三次握手,四次挥手6、重排与重绘7、用css实现一个三角形8、常见的flex布局,有哪些功能9、用css实现一个水平垂直居中10、null与undefined的区别11、虚拟dom12、深拷贝与浅拷贝13、es6新增的功能15、async await 与promise。_今年的前端面试难不难