之前总结了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是 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