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

智能推荐

最新遇到了kingcms攻击-有上传文件和创建函数_$power=$mix('',$uri);-程序员宅基地

文章浏览阅读427次,点赞8次,收藏8次。函数创建一个匿名函数,该函数接受两个参数,但在这里只传递了一个空字符串和一个二进制数据字符串。函数将尝试执行字符串"rot13"作为PHP代码,这会导致错误,因为"rot13"不是有效的PHP代码。总的来说:就是通过加密和解密的方式,create_function,并执行了!来执行动态生成的代码通常是不安全的,因为它容易受到代码注入攻击。meiyuan/css/head.php,重点来了!的值,经过ROT13编码后,它会变成"rot13",然后。是一个PHP函数,用于动态地创建一个匿名函数。_$power=$mix('',$uri);

JS 监听滚动条事件_js监听滚动条滚动事件-程序员宅基地

文章浏览阅读1.1w次,点赞4次,收藏13次。JS 监听滚动条事件获取滚动条位置代码监听滚动条方法效果获取滚动条位置代码/*** 获取滚动条位置*/function getScrollTop() { var scrollPos; if (window.pageYOffset) { scrollPos = window.pageYOffset; } else if (document.compatMode && document.compatMode != 'BackCompat'_js监听滚动条滚动事件

面试官:说一下script 标签中 defer(推迟) 和 async(异步) 的区别_script defer-程序员宅基地

文章浏览阅读2k次,点赞15次,收藏12次。script 标签中 defer 和 async 的区别:“在解析HTML文档过程中,defer和async标注的脚本都会立即下载。不同的是……”_script defer

智能电话客服机器人的交互流程_交互机器人项目交付流程-程序员宅基地

文章浏览阅读2.7k次。就目前来说语音对话形式的智能客服机器人已经越来越多。人们想要处理什么事情,电话打到客服中心大多数的第一站是智能客服机器人,实在复杂的才有可能会交给人工客服处理。那么你知道智能电话客服机器人是怎么交互的吗?从交互形式来划分,智能客服包括纯语音(如联信志诚智能客服机器人),纯文本(如小冰),纯可视化界面(如一些电商的客服,完全通过界面交互来完成对话)。交互形式没有好坏,这一点同非AI产品一样,根据用户使用场景选择最合适的形式即可。从产品定义出发,智能客服类产品,最根本的价值在于以低成本取代人工客服工作中大_交互机器人项目交付流程

Nexus-vPC基础实验-程序员宅基地

文章浏览阅读541次。一、实验拓扑:由于条件有限,使用两个N5K做基本的vPC实验,Peer Keepalive Link使用的是两个Nexus 5K的Mgm0接口。二、配置步骤:1、先构建vPC domain,并在domain下定义role优先级、system优先级、PKL。2、然后配置Port-channel作为PL。3、配置vPC成员端口,配置vPC。4、配置Catalyst4500X交换机的Port-c..._nexus vpc

XML文件以及DTD的编写_xml的dtd文件怎么写-程序员宅基地

文章浏览阅读2.8k次。感谢阅读 转载请注明出处:http://blog.csdn.net/SX_csu2016sw1.XML:1.1XML简介:1.1是一种可扩展标记性语言,类似于HTML,设计的宗旨是描述以传输数据,并不是用来显示数据1.2XML标签没有预定义,需要开发人员自己定义1.3XML文件遵循得失W3C于2000发布的XML1.0规范1.2XML用途:常用于Client/Sever之间传输数据,使得_xml的dtd文件怎么写

随便推点

Datagrip连接Oracle_datagrip怎么连接oracle-程序员宅基地

文章浏览阅读681次。datagrip连接oracle报错_datagrip怎么连接oracle

SystemVerilog 验证-测试平台编写指南学习笔记(3):连接设计和测试平台_system verilog unit_test-程序员宅基地

文章浏览阅读1.3k次。文章目录1 为什么需要更高层次的方法连接 Testbench 与 DUT?2 SystemVerilog 接口2.1 什么是接口?2.2 接口怎么连接?2.3 接口的优缺点?3 SystemVerilog 控制通信中时序问题地结构?3.1 使用时钟块控制同步信号地时序4 SystemVerilog 引入的新的时间片的划分方式?5 SystemVerilog 新增的结束仿真的方法?6 接口中时钟块的信号是怎么同步的?7 为什么在程序(program)中不允许使用always块?8 SystemVerilog _system verilog unit_test

2018.11.04 洛谷P2679 子串(线性dp)-程序员宅基地

文章浏览阅读31次。传送门为什么前几年的noipnoipnoip总是出这种送分题啊?这个直接线性dpdpdp不就完了吗?f[i][j][k][0/1]f[i][j][k][0/1]f[i][j][k][0/1]表示当前在第iii个位置,已经匹配到了第jjj个位置,已经使用了kkk段,当前这个字符没用用/用了。然后分情况简单转移一下就行了。注意可以滚动数组优化空..._考虑两个字符串右对齐的最佳解法。例如,有一个右对齐方案中字符串是aaddefgghc和a

Linux压缩与解压缩-程序员宅基地

文章浏览阅读348次,点赞10次,收藏7次。1.常用压缩文件的扩展名有哪些?2.常用的压缩解压缩工具有哪些?3.压缩解压缩工具之间有什么区别?4.常用压缩解压缩命令?

angularjs框架的悬浮提示框实现_angluarjs提示框怎么写-程序员宅基地

文章浏览阅读1.2w次。angularjs框架的悬浮提示框实现第一步:需要添加js引用:第二步:在JS中引用这个控件有的可以这样写:reliers.push("angular-popups");有的可以这样写:angular.module('examples', ['angular-popups']);第三步:写html代码如果只是单个显示那很简单,如下:打开气泡hell_angluarjs提示框怎么写

80%保研er都存在的误区:保本校不需要参加夏令营?_本校保研需要参加夏令营吗-程序员宅基地

文章浏览阅读1.4k次。如果在夏令营期间拿到优营就相当于提前拿到offer了,只需要具备推免资格便可被拟录取为文献中心的研究生,因此对于这些院校而言,夏令营也是拿到offer的机会之一,所以尽管是想保本校,也需要按照学院颁发的通知来参加夏令营。,通过这些学术交流活动,以及穿插其中的一些笔试和面试,会促使专业导师与参营营员之间得到较为深入的交流和了解,保研er在与其他学校的老师的交流过程中可能会碰撞出新的火花,在高校中,即使是同一个专业,也会有很多导师,尽管是本校学生可能也无法很好的了解所有的导师。,看见不一样的学术氛围。_本校保研需要参加夏令营吗

推荐文章

热门文章

相关标签