C++字符串流stringstream与string知识介绍与用法小结

之前总结了C++的文件输出输入流的相关知识,通过介绍底层的streambuf缓冲区,从而与stringstream流(字符串流)联系了起来,本文就对此进行简单的介绍。


首先介绍string
string 是 C++ 提供的字符串类,和 C 类型的字符串相比,除了有不限长度的优点外,还有其他许多方便的功能,其可以看成类似STL里vector数组的一种容器,可以方便的进行数据的增删改查,并可以进行排序、交换与遍历。要使用 string, 必须包含头文件string,并包含std命名空间:

#include 
using namespace std;

声明一个字符串变量为(本质上也可以理解为class string的一个对象,包含许多的成员函数):

string str;
//可以在声明时进行初始化
string str = "Hello";

要输出str的单个字符,可以与传统C的字符串一样采用下标运算str[i]的形式,也可以采用成员函数(str.at(i))的形式,不同的是[]运算不会检查索引i是否越界,而at()函数会检查,使用无效时会抛出out_of_range异常。

同时,string类型的字符串是不以‘\0’结尾的,因此若str有三个字符,传统C语言的字符串的str[3]是字符‘\0’,但是string类型的只能到str[2],str[3]是没有定义的,而str. at(3)会提示越界奔溃。

C++ string类型字符串与C类型的字符串的简单对比如下:

功能 C++ string C字符数组
定义字符串 string str; char str[100];
单个字符输出 str[i] / str.at(i) str[i]
字符串长度 str.length() / str.size() strlen(str)
读取一行 getline(cin,str) gets(str)
赋值 str = “Hello”; strcpy(str,“Hello”);
连接字符串 str = str + “Hello” strcat(str,“Hello”);
比较字符串 str == “Hello”; strcmp(str,“Hello”);

要使用strlen()、strcpy()函数需要包含C语言的字符串操作函数头文件:

#include 
using namespace std;
//上述两行代码等价于下面一行代码
#include 

C++字符串与C字符串

C++ string类提供了c_str()、data()和copy()这三个成员函数用于将C++字符串string转换为C字符串C_string,其

函数 功能
c_str() 返回一个以‘/0’结尾的字符数组
data() 以字符数组的形式返回字符串内容,但并不添加’/0’
copy() 字符串的内容复制或写入既有的c_string或字符数组内
string str = "Hello World!";
const char* p1 = str.c_str();
const char* p2 = str.data();
const char* p3=new char[10];
str.copy(p3,5,0);
//函数原型:copy(char *s, int n, int pos = 0)
//把当前串中以pos开始的n个字符拷贝到以s为起始位置的字符数组中,返回实际拷贝的数目 

string还可以方便的改变字符串的容量大小,通过调用成员函数resize()可以重设string的容量。

string str="Hello";
str.resize(3);

string可以很方便的查找字符串中的字符或者子串,其是通过成员函数find()和substr()实现的,
find()函数是从str第3个位置查起,找到子串后,返回子串的位置;而substr函数从pos位置(子串开始的位置)开始,截取5个字符,赋值给str2,也就是说,str2的内容将是ssdfs。

string str = "aaaaddddssdfsasdf";  
size_t pos = str.find("ssdf", 3);//注意pos的数据类型string::size_type
//如果没找到,返回一个特殊的标志npos
// 可以用if(pos != string::npos)则表示找到。
string str2 = str.substr(pos, 5);

string还有很多的功能强大的函数,具体的用法可以参考以下的博文:
https://www.cnblogs.com/zxouxuewei/p/5728720.html


二、stringstream

stringstream是 C++ 提供的一个字符串流(stream),和之前学过的iostream、fstream有类似的操作方式,要使用stringstream,必须包含其头文件:

#include 
using namespace std;
stringstream ss;

< sstream > 库定义了三种类:istringstream、ostringstream和stringstream,分别用来进行流的输入、输出和输入输出操作。另外,每个类都有一个对应的宽字符集版本。一般情况下使用stringstream就足够,因为字符串要频繁的涉及到输入输出。

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

与文件流fstream类似,通过插入器(<<)和析取器(>>)这两个运算符可以直接对stringstream上的数据输入输出,而将stringstream中的全部数据输出则是使用成员函数str(),其有两种形式:
1、void str() //无参形式,用于将stringstream流中的数据以string字符串的形式输出
2、void str (const string& s)//以字符串为参数,用以覆盖stringstream流中的数据
特别需要注意的是:

// 字符串流清零,将流中的数据全部清除
ss.str(""); 

示例代码:

#include 
#include 
#include 
using namespace std;
int main()
{
stringstream ss;
ss << "hello ";
ss << "world!";

std::cout << ss.str() << std::endl;
// 对stringstream而言,operator<< 是一直往字符串流中写字符
// 而不是覆盖之前输入的字符,这一点不同于str()成员函数方法,str()函数创建的是一个临时的string对象
//这个string对象在函数str()语句结束就会被销毁,因而一般使用时应先声明一个string对象s,将str()赋值给s
//const string s=ss.str();//这样会有一个string拷贝的过程
/*又或者是const string& s=ss.str();这样就是用s直接引用了ss.str()这个临时变量,就“延长了临时变量ss.str()的
生命周期”,使得ss.str()生命结束时刻和s一样*/
return 0;
}

ss.clear()成员函数

同文件流fstream中的clear()函数类似,通过clear()成员函数可以清除流的错误状态,主要用在stringstream重复使用时或者多个stringstream对象构造时清空,不然之前的缓冲就停留在输入输出流中。

ss.setstate(std::ios::eofbit);//设置流的状态标志位
std::cout << ss.rdstate() << std::endl;//获取当前流的状态标志位
// 结果为1
ss.clear();
std::cout << ss.rdstate() << std::endl;
// 结果为0

在对同一个stringstream对象重复赋值,就需要先对流使用clear()函数清空流的状态,此时流占用的内存没有改变,会一直增加(stringstream不主动释放内存),若想改变内存(一般是清除内存,减少内存消耗),需要再配合使用str("")清空stringstream的缓存。

stringstream stream;
    int a,b;
    ss<<"80";//向流输出数据(写入)
    ss>>a;//从流输入数据到a
    cout<<"Size of ss = "<<ss.str().length()<<endl;//ss.str()返回一个string对象,再调用其成员函数length()
    ss.clear();//清空流
    ss.str("");//清空流缓存
    cout<<"Size of ss = "<<ss.str().length()<<endl;
    ss<<"90";//重新赋值
    ss>>b;
    cout<<"Size of ss = "<<ss.str().length()<<endl;  

运行结果:

Size of ss = 2
Size of ss = 0
Size of ss = 2
80
90

stringstream与fstream

通过重载的<<和>>运算符可以将文件流中的数据输出到C++字符串中,它们之间的媒介是缓冲区streambuf,可由流的成员函数rdbuf()读取。

#include 
#include //stringstream流的头文件
#include 
using namespace std;
int main()
{
        string str;
        ifstream in;
        in.open("Hello.txt");
        //读取文件的缓冲内容到数据流中
        stringstream ss;
        ss << in.rdbuf();
        in.close();//关闭文件
        str = ss.str();//将stringstream流中的数据赋值给string类型字符串
        const char* p = str.c_str();//将字符串内容转化为C_string类型
        return 0;
}

stringstream通常是用来做数据转换的,用于字符串与其他变量类型的转换,相比c库的转换,它更加安全,自动和直接。

#include 
#include 
#include 
using namespace std;
int main()
{
    string str1("How are you? 123 1 4.368");
    stringstream ss(str1);//构造函数初始化
    cout<<ss.str1()<<endl;
    string str2;
    for(int i=0;i<3;i++)
    {
    	ss>>str2;
    	cout<<str2<<" ";
	}
	int a;
	ss>>a;
	cout<<a<<endl;
	bool b;
	ss>>b;
	cout<<b<<endl;
	float c;
	ss>>c;
	cout<<c<<endl;	
	ss.clear();
	ss.str1("I am fine!");//重新赋值
	while(ss>>str2)//不断读取
	{
		cout<<str2<<" ";
	}		
}

运行结果:

How are you? 123 1 4.368
How are you?
123
1
4.368

由上面的代码可知,从stringstream流中的数据输入字符串到一个变量里,是以遇到空格跳到下一个字符串的这样的形式连续读取的。

参考博文:
https://blog.csdn.net/sunshineacm/article/details/78068987
https://blog.csdn.net/alex123980/article/details/51707220
https://blog.csdn.net/yasi_xi/article/details/18401983

你可能感兴趣的:(C++)