头文件:
#include<string>
string的基本概念概念:
概念:string
是c++中的字符串类型,相当于C语言中的char *
,其本质是一个封装好的类
string
和char*
的区别:
char*
是一个指针string
是一个内部封装了char*
的类,用来管理这个字符串,是一个char*
型容器char*
为静态存储,大小被固定string
为动态存储(但是在堆和栈中都存有)
特点:
string
类内部封装了很多成员函数
例如:查找find,拷贝copy,删除delete,替换replace,插入insertstring
管理char*
所分配的内存,不用担心赋值越界和取值越界等问题,由类内部负责
string的构造函数
函数原型:
- string(); 默认构造,创建一个空字符串
- string(const char* s); 使用字符串初始化
- string(const string& str); 拷贝构造,使用一个string对象初始化另一个string对象
- string(int n,char c); 使用n个字符c初始化
实例:
#include<iostream>
using namespace std;
int main()
{string str1; //1string str21("aaaaa"); //2string str22="bbbbb";string str3(str21); //3string str4(5, 'c'); //4cout << "str21=" << str21 <<"\nstr22=" << str22 << "\nstr3=" << str3 << "\nstr4=" << str4 << endl;return 0;
}
运行结果:
str21=aaaaa
str22=bbbbb
str3=aaaaa
str4=ccccc
string的赋值操作
函数原型:
- string& operator=(const char* s); char* 类型字符串赋给当前字符串
- string& operator=(const string& str); string类型字符串str赋给当前字符串
- string& operator=(char c); 单个字符赋给当前字符串
- string& assign(const char* s); char类型字符串赋给当前字符串
- string& assign(const char* s,int n); 把字符串s前n个字符赋给当前字符串
- string& assign(const string& str); string类型字符串str赋给当前字符串
- string& assign(int n,char c); 把n个字符c赋给当前字符串
实例:
#include<iostream>
using namespace std;
int main()
{string str[7];str[0] = "aaaaa"; //1str[1] = str[0]; //2str[2] = 'a'; //3str[3].assign("bbbbb"); //4str[4].assign("ccccc", 3); //5str[5].assign(str[4]); //6str[6].assign(5, 'd'); //7cout << "\nstr[0]=" << str[0] << "\nstr[1]=" << str[1] << "\nstr[2]=" << str[2] << "\nstr[3]=" << str[3]<< "\nstr[4]=" << str[4] << "\nstr[5]=" << str[5] << "\nstr[6]=" << str[6] << endl;cout << "str[0][0]=" << str[0][0] << endl;return 0;
}
运行结果:
str[0]=aaaaa
str[1]=aaaaa
str[2]=a
str[3]=bbbbb
str[4]=ccc
str[5]=ccc
str[6]=ddddd
str[0][0]=a
string字符串的拼接
函数原型:
- string& operator+=(const char* s); 重载+=
- string& operator+=(const char c);
- string& operator+=(const string& str);
- string& append(const char* s); 把字符串s连接到当前字符串尾
- string& append(const char* s,int n); 把字符串s前n个字符连接到当前字符串尾
- string& append(const string& str);
- string& append(const string& str,int pos,int n); 把字符串str从pos开始的n个字符连接到当前字符串尾
实例:
#include<iostream>
using namespace std;
int main()
{string str1;string str2 = " C++";string str3 = " ,yesssssss";str1 += 'I'; //2,str1 += " love"; //1str1 += str2; //3str1.append(" and"); //4str1.append(" algorithm aaa",10); //5str1.append(str3); //6str1.append(str3, 0, 5); //7cout << str1;return 0;
}
运行结果:
I love C++ and algorithm ,yesssssss ,yes
string查找与替换
- 查找函数
find
和rfind
,功能是查找指定字符串是否存在,若存在返回出现的下标位置,若不存在返回-1 - 替换函数
replace
,在指定位置替换字符串中某些字符
函数原型:
- int find(const string& str,int pos = 0);从pos开始查找字符串str第一次出现的位置
使用:int num = str1.find(str2,pos);以下几个使用类似 - int find(const char* s,int pos=0); 从pos开始查找字符串s第一次出现的位置
- int find(const string& str,int pos = 0,int n);从pos开始查找字符串str的前n个字符第一次出现的位置
- int find(const char c,int pos=0); 从pos开始查找字符c第一次出现的位置
- int rfind(const string& str,int pos = npos);从pos开始查找字符串str最后一次出现的位置
- int rfind(const char* s, int pos = npos); 从pos开始查找字符串s最后一次出现的位置
- int rfind(const string& str,int pos,int n);从pos开始查找字符串str的前n个字符最后一次出现的位置
- int rfind(const char c,int pos=0); 从pos开始查找字符c最后一次出现的位置
- string& replace(int pos,int n,const string& str);用字符串str替换从pos开始的n个字符
使用: str1.replace(pos,n,str2); - string& replace(int pos,int n,const char* s);用字符串s替换从pos开始的n个字符
实例:
#include<iostream>
using namespace std;
int main()
{string str1 = "abcdEabcdef";int pos = str1.find("cd");if (pos != -1){cout << "pos=" << pos << endl;}else cout << "未找到" << endl;pos = str1.rfind("cd");if (pos != -1){cout << "pos=" << pos << endl;}else cout << "未找到" << endl;str1.replace(2, 3, "1234");//用"1234"替换从第二个位置开始的3个字符cout << str1 << endl;return 0;
}
运行结果:
pos=2
pos=7
ab1234abcdef
string的比较
比较方式:
字符串之间的比较是逐个字符按照ASCII码大小进行比较的,调用str1.compare(str2)
成员函数。
函数原型:
int compare(const string& str);
与字符串str比较int compare(const char* s);
与字符串s比较
当两个字符串相等时(即字符串完全相同)函数返回 0 ;
当str1大于str2时函数返回 1;
当str1小于str2时函数返回 -1;
特别地,判断两个string类字符串的大小还可以使用重载的运算符 ==、!=、>、<、>=、<= 进行比较。
如:str1 == str2、str1 > str2、str1 <= str2等
实例:
#include<iostream>
using namespace std;
int main()
{string str1 = "abcdefg";string str2 = "bcdef";if (str1.compare(str2) == 0)//或者使用 str1==str2cout << "字符串相等\n";else if (str1.compare(str2) > 0)//或者使用 str1 > str2cout << "str1较大\n";elsecout << "str1较小\n";if (str1.compare("abcdefg") == 0)cout << "字符串相等\n";else if (str1.compare("abcdefg") > 0)cout << "str1较大\n";elsecout << "str1较小\n";return 0;
}
运行结果:
str1较小
字符串相等
string的存取
字符串的存取即 string中单个字符的访问与修改
函数原型:
char& operator[](int n)
通过[]方式访问与修改字符char& at(int n)
通过at方式获取字符
实例:
#include<iostream>
using namespace std;
int main()
{string str = "abcde";for (int i = 0; i < str.size(); ++i) //size() 是获取字符串大小的函数{str[i] = 'A'+i; //通过[]方式修改cout << str[i] << " "; //通过[]方式访问}cout << endl;for (int i = 0; i < str.size(); ++i) {str.at(i) = 'a' + i; //通过at方式修改cout << str.at(i) << " "; //通过at方式访问}return 0;
}
运行结果:
A B C D E
a b c d e
string的插入和删除
函数原型:
- string& insert(int pos,const char* s); 从pos位置开始插入字符串s,pos均从0开始计数
- string& insert(int pos,const string& str); 从pos位置开始插入字符串str
- string& insert(int pos,int n,char c); 从pos位置开始插入n个字符c
- string& erase(int pos,int n=npos); 从pos位置开始删除n个字符
实例:
#include<iostream>
using namespace std;
int main()
{string str = "hello";str.insert(2, "123");cout << "插入后:" << str << endl;str.erase(2,3);cout << "删除后:" << str << endl;return 0;
}
运行结果:
插入后:he123llo
删除后:hello
string类对象的容量操作
函数名称 | 功能说明 |
---|---|
size | 返回字符串的有效长度。 |
length | 返回字符串的有效字符长度。 |
capacity | 返回空间的总大小。 |
empty | 检测字符串是否为空串,是返回true,否返回false。 |
clear | 清空有效字符,但空间保留。 |
reserve | 为字符串预留空间。 |
resize | 将有效字符的个数改为n个,多出的空间用字符c填充。 |
实例1:
#include<iostream>
using namespace std;
int main()
{string s1("bit education");string s2("C++");cout << s1.size() << endl;cout << s2.size() << endl;cout << s1.length() << endl;cout << s2.length() << endl;//在C++中size函数与length函数等同cout << s1.max_size() << endl;cout << s2.max_size() << endl;cout << s1.capacity() << endl;cout << s2.capacity() << endl;s1.clear(); cout << s1.size() << endl;//size减为0 cout << s1.capacity() << endl;//capacity空间依旧保留return 0;
}
运行结果:
13
3
13
3
4611686018427387897
4611686018427387897
13
3
0
13
实例2:使用reserve函数进行容量操作:
- reserve()函数并不改变字符串的实际长度,也不会初始化新增的内存区域,只是为将来的添加操作预留了足够的内存空间。
- 若reserve函数分配的内存小于字符串当前的内存,实际上并不会改变当前字符串的内存大小。
未使用reserve的情况下:
#include<iostream>
using namespace std;
int main()
{string s;size_t sz = s.capacity();cout << "making s grow:" << endl;for (size_t i = 0; i < 100; i++){s.push_back('c');if (sz != s.capacity()){sz = s.capacity();cout << "capacity changed:" << sz << endl;}}return 0;
}
运行结果:字符串每达到一定大小后就会扩容
making s grow:
capacity changed:1
capacity changed:2
capacity changed:4
capacity changed:8
capacity changed:16
capacity changed:32
capacity changed:64
capacity changed:128
使用reserve的情况下:
#include<iostream>
using namespace std;
int main()
{string s;s.reserve(100);size_t sz = s.capacity();cout << "making s grow:" << endl;for (size_t i = 0; i < 100; i++){s.push_back('c');if (sz != s.capacity()){sz = s.capacity();cout << "capacity changed:" << sz << endl;}}return 0;
}
运行结果:字符串沿着reserve预留空间增长,没有扩容
making s grow:
实例3:使用resize函数进行容量操作
- 若调用 resize 函数时指定的大小小于当前字符串的大小,则 resize() 函数会截断当前字符串,使其大小等于指定的大小。这时,被截断的部分字符会被删除,内部存储区域的大小也会被缩小到刚好能够容纳截断后的字符串。
- 当内存重新分配时,会将原有的字符串内容复制到新的存储区域中。因此,如果 resize() 函数调整了内部存储区域的大小,则该函数的时间复杂度是O(len),其中len是当前字符串的大小。
- resize函数重新分配的内存区域,新增的部分会被初始化。
#include<iostream>
using namespace std;
int main()
{string s;s.resize(90);size_t sz = s.capacity();cout << "making s grow:" << endl;for (size_t i = 0; i < 100; i++){s.push_back('c');if (sz != s.capacity()){sz = s.capacity();cout << "capacity changed:" << sz << endl;}}return 0;
}
运行结果:由于新增区域被初始化,push_back函数会在初始化之后的地方开始尾增
making s grow:
capacity changed:180
capacity changed:360
string类对象的遍历操作
函数名称 | 功能说明 |
---|---|
operator[] | 返回pos位置的字符,const string类对象调用。 |
begin + end | begin获取一个字符的迭代器 + end获取最后一个字符下一个位置的迭代器。 |
rbegin + rend | begin获取一个字符的迭代器 + end获取最后一个字符下一个位置的迭代器。 |
基于范围的for | C++11所支持的更简洁的基于范围for的遍历方式。 |
[下标]遍历
#include<iostream>
using namespace std;
int main ()
{std::string str ("Test string");for (int i=0; i<str.length(); ++i){std::cout << str[i];}return 0;
}
迭代器
对于 std::string 的迭代器来说,它支持随机访问,因此可以像指针那样进行指针算术运算。例如:使用 it += 1 或 it -= 1 来移动迭代器的位置。因此,如果只是移动迭代器一个位置,使用指针算术运算比使用 std::advance 函数更加方便和高效。
不过需要注意的是,并非所有的迭代器都支持随机访问。对于某些容器(例如 std::list),其迭代器只支持前向迭代,不支持随机访问和指针算术运算,此时就需要使用 std::advance 函数来移动迭代器的位置。因此,在编写代码时,需要根据具体情况选择合适的方法来移动迭代器。
实例:
#include<iostream>
using namespace std;
int main()
{string s1("bit education");string::iterator it = s1.begin();//auto it=s1.begin();auto自动推导it是迭代器//读取while (it != s1.end()){cout << *it << " ";it++;}cout << endl;//写入it = s1.begin();while (it != s1.end()){*it = *it + 2;it++;}cout << s1 << endl;return 0;
}
运行结果:
b i t e d u c a t i o n
dkv"gfwecvkqp
基于范围的for循环
#include<iostream>
using namespace std;
int main() //范围for的遍历 C++11原理是迭代器
{string s1("Hello World!");for (auto s : s1) //依次取出容器s1里面的字符给s{cout << s << " ";}cout << endl;for (auto s : s1){s = s + 1;cout << s << " ";}cout << endl;return 0;
}
运行结果:
H e l l o W o r l d !
I f m m p ! X p s m e "
反向迭代器
- 反向迭代器(reverse iterator)是一种能够以相反的顺序遍历容器元素的迭代器,即从最后一个元素开始遍历,一直到第一个元素。C++ 标准库中提供了 std::reverse_iterator 类来实现反向迭代器。
- std::reverse_iterator 是一个适配器类,它将一个普通的迭代器包装成反向迭代器。
- 通过调用std::make_reverse_iterator 函数可以将一个正向迭代器包装成反向迭代器。
#include<iostream>
using namespace std;
int main() //反向迭代器,倒着遍历
{string s1("bit education");string::reverse_iterator rit = s1.rbegin();while (rit != s1.rend()){cout << *rit << " ";rit++;}cout << endl;return 0;
}
const修饰的迭代器
#include<iostream>
#include<typeinfo>
using namespace std;
//将字符串数字转化为整形
int StringInt(const string& str)
{int result = 0;string::const_iterator it = str.begin();while(it != str.end()){result = result * 10 + (*it - '0');it++;}return result;
}
int main()
{string s("123456");cout << StringInt(s) << endl;cout << typeid(StringInt(s)).name() <<endl;return 0;
}
运行结果:
123456
i
在C++中,可以使用 typeid
运算符来获取一个表达式的类型信息。具体来说,可以使用 typeid(expression)
来获取 expression
的类型信息,返回值是一个 std::type_info
类型的对象,可以通过其 name()
成员函数来获取类型的名称。
实例:
#include <iostream>
#include <typeinfo>void foo(int x, double y, const char* z) {std::cout << "x: " << typeid(x).name() << std::endl;std::cout << "y: " << typeid(y).name() << std::endl;std::cout << "z: " << typeid(z).name() << std::endl;
}int main() {foo(42, 3.14, "hello");return 0;
}
运行结果:
x: i
y: d
z: PKc
其中,i
表示int
类型,d
表示double
类型,PKc
表示const char*
类型。需要注意的是,typeid
返回的类型名称可能是编译器特定的,不同编译器可能会有不同的实现。
此段来源于:https://blog.csdn.net/Dontla/article/details/130457108
string的子串
函数原型:
string substr(int pos,int n=npos);
返回由pos开始的n个字符组成的子串,默认的npos是从pos到字符串结尾的所有字符的个数
- s.substr(); 返回s的全部内容
- s.substr(11); 从索引11往后的子串
- s.substr(5,6); 从索引5开始6个字符
实例:
#include<iostream>
using namespace std;
int main()
{//获取QQ邮箱前面的QQ号string str = "123456789@qq.com";int pos = str.find("@");string QQnumb = str.substr(0, pos);cout << "邮箱为:" << str << endl;cout << "QQ号为:" << QQnumb << endl;return 0;
}
运行结果:
邮箱为:123456789@qq.com
QQ号为:123456789
C字符串、string串、stringstream之间的关系
首先必须了解,string可以被看成是以字符为元素的一种容器。字符构成序列(字符串)。有时候在字符序列中进行遍历,标准的string类提供了STL容器接口。具有一些成员函数比如begin()、end(),迭代器可以根据他们进行定位。注意,与char不同的是,string不一定以NULL(‘\0’)结束。string长度可以根据length()得到,string可以根据下标访问。所以,不能将string直接赋值给char。
string转换成const char *
如果要将字面值string直接转换成const char *类型,string有2个函数可以运用:一个是.c_str(),一个是data成员函数。
c_str()函数返回一个指向正规C字符串的指针,内容与本string串相同。这是为了与C语言兼容,在C语言中没有string类型,故必须通过string类对象的成员函数c_str()把string 对象转换成C中的字符串样式。注意:一定要使用strcpy()函数等来操作方法c_str()返回的指针
string str = "Hello World";
const char *ch1 = str.c_str();
const char *ch2 = str.data();
此时,ch1与ch2的内容将都是”Hello World”。但是只能转换成const char*,如果去掉const编译不能通过。
string转换成char *
C++提供的由C++字符串得到对应的C_string的方法是使用data()、c_str()和copy(),其中
- data()以字符数组的形式返回字符串内容,但并不添加’\0’。
- c_str()返回一个以’\0’结尾的字符数组,返回值是const char*
- copy()则把字符串的内容复制或写入既有的c_string或字符数组内。
C++字符串并不以’\0’结尾。我的建议是在程序中能使用C++字符串就使用,除非万不得已不选用c_string。
如果要转换成char*,可以用string的一个成员函数strcpy实现。
string str = "Hello World";
int len = str.length();
char *data = new char[len+1]; //这里+1还是不+1需要注意
strcpy(data, str.c_str()); // const char *data = new char[len+1]; strcpy(data, str);
此时,data中的内容为”Hello World”使用c_str()要么str赋给一个const指针,要么用strcpy()复制。
char *转换成string
string类型能够自动将C风格的字符串转换成string对象:
string str;
const char *pc = "Hello World";
str = pc;
printf(“%s\n”, str); //此处出现错误的输出
cout<<str<<endl;
不过这个是会出现问题的。有一种情况我要说明一下。当我们定义了一个string类型之后,用printf(“%s”,str);输出是会出问题的。这是因为“%s”要求后面的对象的首地址。但是string不是这样的一个类型。所以肯定出错。
用cout输出是没有问题的,若一定要printf输出。那么可以这样:
printf("%s",str.c_str());
char[ ] 转换成string
这个与char*的情况相同,也可以直接赋值,但是也会出现上面的问题,需要同样的处理。
字符数组转化成string类型:
char ch [] = "ABCDEFG";
string str(ch); //也可string str = ch;
或者
char ch [] = "ABCDEFG";
string str;
str = ch; //在原有基础上添加可以用str += ch;
string转换成char[ ]
string对象转换成C风格的字符串:
const char *str = s.c_str();
这是因为为了防止字符数组被程序直接处理c_str()返回了一个指向常量数组的指针。
由于我们知道string的长度可以根据length()函数得到,又可以根据下标直接访问,所以用一个循环就可以赋值了,这样的转换不可以直接赋值。
string str = "Hello World";
int len=str.length();
char ch[255]={};
for( int i=0;i<str.length();i++)
ch[i] = str[i];
ch[len+1] = '\0';
printf("%s\n", ch);
cout<<ch<<endl;
stringstream与string间的绑定
stringstream strm;
string s;
strm<<s; // 将s写入到strm
strm>>s; // 从strm读取串写入s
strm.str(); // 返回strm中存储的string类型对象
strm.str(s); // 将string类型的s复制给strm 返回void
char* cstr; // 将C字符数组转换成流
string str(cstr);
stringstream ss(str);
详细了解stringstream请看:【C++】stringstream
参考博文:
https://blog.csdn.net/qq_52324409/article/details/121404001
https://blog.csdn.net/qq947467490/article/details/130183703
https://blog.csdn.net/soinlove36/article/details/119796794
https://blog.csdn.net/hero_myself/article/details/52313617