
一、基本概念
(1)using
C++11中引入了using。在起别名上完全等价于typedef。而且更加简洁。
语法:
cpp
using 新名字 = 旧名字;
cpp
int main() {
using i = int;//用i起别名
i a = 3;
cout << a << endl;
}
(2)string
①原型
cpp
typedef basic_string<char> string;
cpp
using string = basic_string<char>;
string是被using/typedef出来的。basic_string<char>一个模板类,存在于C++标准库里。包含各种处理字符串的方法。底层是字符数组顺序表。使用时要包含头文件string
二、string的构造函数
(1)无参的默认构造

默认为空
cpp
int main() {
string a;//无参的初始化(初始化为空)
cout << a << endl;//输出空
}
(2)有参的构造

cpp
int main() {
const char* s = "sss";
string s1("abc");
string s2(s);
cout << s1 << endl;
cout << s2 << endl;
}
这两种构造方式是同一种构造不同的方法。
(3)拷贝构造

cpp
int main() {
string s1("abc");
string s2(s1);//用s1构造s2
cout << s1 << endl;
cout << s2 << endl;
}
(4)字串构造函数

npos是len的缺省值,npos是size_t的-1,在32位操作系统下值是2^32-1
用已有对象构造新的对象。pos表示拷贝的起始位置,len表示拷贝的字符长度(个数)。(超出len的实际值一律拷到最后一个字符)
cpp
int main() {
string s1("abcdef");
string s2(s1,3,2);//从下标3的位置开始拷贝2个字符
cout << s2 << endl;//输出de
}
(5)字符序列构造
cpp
int main() {
string s(20, 'z');
cout << s << endl ;//用20个z构造s
}

用已有的字符串构造对象。n是字符串的长度,n不能大于字符串有效长度。
cpp
int main() {
const char* arr1 = "abcdef";//有效长度是7
char arr2[] = { 'a','b','c','d','e','f' };//有效长度是6
string s1(arr1,7);//无报错,n没有超出有效长度
cout << arr1 << endl;
string s2(arr2, 7);//报警告,n超出了有效长度(超出部分打印乱码)
cout << arr2 << endl;
}
(6)填充构造

用n个字符c构造对象
cpp
int main() {
string s(20, 'z');
cout << s << endl ;//用20个z构造s
}
三、string的析构函数
string的析构函数就只有一个,一般会自动调用。
四、运算符重载
(1)重载"+"

用两个已有对象的进行字符拼接,构造出新的对象。
cpp
int main() {
string s1("hello ");
string s2("world");
string s3(s1 + s2);//s1 + s2 创建一个临时对象,用临时对象构造s3(拷贝构造)
cout << s3 << endl;
}
用已有的字符和对象构建出新的对象。
cpp
int main() {
string s1("abc");
string s2 = "000" + s1;
cout << s2 << endl;//输出000abc
const char* s = "def";
string s3 = s1 + s;
cout << s3 << endl;//输出abcdef
}
(2)重载"+="

假设已有A,B对象。重载+= 表示在A的字符串后追加B的字符串。也可以追加某个字符/字符串。
cpp
int main() {
string s1("hello ");
string s2("world");
cout << s1 << endl;
s1 += s2;//hello 后追加world
cout << s1 << endl;//输出hello world
}
(3)重载"[]"
可以将对象中的字符串想象成一个字符数组。用下标可以访问/修改其中的某个字符,超出范围会触发非法访问。
cpp
int main() {
string s("abcdef");
cout << s[5] << endl;//访问f
cout << s[6] << endl;//访问\0
cout << s[7] << endl;//非法访问,造成程序崩溃
}
(4)"<<"和">>"
输入和输出字符串。
cpp
int main() {
string s;
cin >> s;
cout << s << endl;
}
(5)重载"=="和"!="
比较两个对象中的内容是否相同/不相同。
cpp
int main() {
string A("abc");
string B("abcd");
if (A == B)
cout << "A和B中的内容相同" << endl;
else if(A != B)
cout << "A和B中的内容不相同" << endl;
}
(6)"<"和">" "<="和">="
< 和 > :比较两个对象内容的大小。(比较方式和strcpy是一致的)
<= 和 >= :在strcpy的比较机制上加了=
五、size和length
(1)概念


C++的string中,size和length都是它的成员函数,都表示的是这个字符串的长度。
(2)遍历
cpp
int main() {
string s("abcdef");
for (int i = 0; i < s.size(); i++) {
cout << s[i] << " ";
}
}
cpp
int main() {
string s("abcdef");
for (int i = 0; i < s.length(); i++) {
cout << s[i] << " ";
}
}
六、迭代器(iterator)
(1)概念
存在于容器内部的类,功能相当于容器的"通用指针"。(用法和指针类似。为容器设计的,用来访问、遍历元素)
迭代器共有四种。正向迭代器(普通的和const),反向迭代器(普通的和const的)。这四个迭代器都是容器的内部类。
cpp
int main() {
string s("abcdef");
string::iterator it = s.begin();
while (it != s.end()) {//遍历
cout << *it << " ";
it++;
}
cout << endl;
}
(2)begin和end

begin和end都是string的成员函数,设计出来专门为迭代器用。在正向迭代器中,begin表示指向字符的第一个位置,end表示指向字符的最后一个位置的下一个位置。
(3)反向迭代器
反向(reverse_iterator)迭代器就是迭代器的反向。相当于把"指针"逆置了。
cpp
int main() {
string s("abcdef");
string::iterator it = s.begin();//正向迭代器
while (it != s.end()) {//正向遍历
cout << *it << " ";
it++;
}
cout << endl;
string::reverse_iterator rit = s.rbegin();//反向迭代器
while (rit != s.rend()) {//反向遍历
cout << *rit << " ";
rit++;
}
cout << endl;
}
(4)rbegin和rend
rbegin和rend都是很string的成员函数,设计出来为反向迭代器使用。在反向迭代器中,rbegin表示指向最后一个字符,rend表示指向首字符的前一个位置。
(5)const迭代器
const修饰的迭代器分为两种。const修饰的正向迭代器(const_iterator)和const修饰的反向迭代器(const_reverse_iterator)。const修饰这两种迭代器都表示指向的内容不可修改。
cpp
int main() {
string s1("hello");
string::iterator it = s1.begin();
cout << it[0] << endl;
it[0] = 'c';//正常运行,普通正向迭代器可读可写
cout << it[0] << endl;
string s2("hello");
string::const_iterator rit = s2.begin();
cout << rit[0] << endl;
rit[0] = 'B';//编译报错,const正向迭代器只读
string s3("hello");
string::reverse_iterator rit = s3.rbegin();
cout << rit[0] << endl;
rit[0] = 'C';//正常运行,普通反向迭代器可读可写
cout << rit[0] << endl;
string s4("hello");
string::const_reverse_iterator crit = s4.rbegin();
cout << crit[0] << endl;
crit[0] = 'q';//编译报错,const反向迭代器只读
}
(6)cbegin、cend和crbegin、crend
C++11引入这四个成员函数。cbegin和cend专门服务于const正向迭代器。crbegin和crend专门服务于const反向迭代器。
七、范围for
(1)typeid(变量名/常量).name()
用来查看数据的类型。使用时需包含头文件typeinfo
cpp
#include<typeinfo>
int main() {
cout << typeid('a').name() << endl;//打印char
}
(2)auto
auto是一个关键字,作用是根据右边的内容推导出数据类型。在一些特殊情况下可以简化代码。
cpp
int main() {
auto a = 'a';
cout << typeid(a).name() << endl;//打印char
}
(3)范围for
①概念
C++11引入了范围for,是迭代器遍历的简化写法。一般情况下可以遍历容器和数组。
②语法
cpp
for (元素类型 变量 : 容器) {
}
cpp
int main() {
string s("123456789");
for (auto ch : s) {//范围for遍历容器
cout << ch << " ";
}
}
八、Capacity
(1)capacity

capacity表示当前/扩容的空间大小/空间可存储最大有效字符的个数(除去\0)。但是实际开的空间还是要+1的。
cpp
int main() {
string s1;
cout << s1.capacity() << endl;
string s2("cccccccccccccccccccc");
cout << s2.capacity() << endl;
}
(2)reserve

只会扩容,不会缩容。一般用于提前开空间。
cpp
int main() {
string s;
s.reserve(100);//至少申请可存储100字符的空间
cout << s.capacity() << endl;//capacity只要大于等于100就行
}
cpp
int main() {
string s("hello world");
cout << s << endl;
s.reserve(5);//不会进行缩容,编译器直接忽略这行代码
cout << s << endl;
}
(3)clear

只会清理数据,不会清理内存。
cpp
int main() {
string s("abc");
cout << s.size() << " " << s.capacity() << endl;
s.clear();//只会清理数据,不会清理内存
cout << s.size() << " " << s.capacity() << endl;
}
(4)empty

判断对象中是否存在字符。对象为空返回1,不为空返回0
cpp
int main() {
string s1("abc");
string s2;
cout << s1.empty() << endl;//不为空返回0
cout << s2.empty() << endl;//为空返回1
}
九、修改
(1)append/push_back

push_back只能追加单个字符;append的用法和"+="类似。一般追加字符推荐使用"+=","+="更加便捷。
cpp
int main() {
string s("abc");
s.push_back(' ');
s.push_back('d');//push_back只能追加单个字符
cout << s << endl;//abc d
s.append(" efg");//apprnd和 += 的功能几乎一致
cout << s;//abc d efg
}
(2)insert
①插入字符串

在某个位置插入字符串,第二个参数是对象。
cpp
int main() {
string s1("world");
string s2("hello ");
s1.insert(0,s2);//输出hello world在s1的首位置插入s2
cout << s1 << endl;
}

在某个位置插入字符串,第二个参数是const char*(可以是""包裹的字符串,也可以是const char*的变量)。
cpp
int main() {
string s("qqqq");
s.insert(1, "ooo");
cout << s << endl;//输出qoooqqq
}
②插入单个字符

cpp
int main() {
string s("aaa");
s.insert(0,1,'o');//在s的首位置插入一个字符o
cout << s << endl;//输出oaaa
s.insert(0, 3, '!');//在s的首位置插入三个字符!
cout << s << endl;//输出!!!oaaa
}
(3)erase

删除第pos个位置的len个字符。(有缺省值,一个参数不写默认全删)
cpp
int main() {
string s1("012345");
s1.erase(2,1);//删除2
cout << s1 << endl;//输出12345
string s2(s1);
s2.erase(2);//第二个参数默认为npos,2往后全删
cout << s2 << endl;//输出01
}
(4)replace

从pos个位置开始的len个字符替换成字符串str。
cpp
int main() {
string s("xxxxx");
s.replace(1, 2, "ooo");//位置1往后的两个字符替换成ooo
cout << s << endl;//输出xoooxx
}

从pos个位置开始的len个字符替换成n个字符c。
cpp
int main() {
string s("ooo");
s.replace(1,1,2,'p');//输出oppo
cout << s;
}
(5)find



寻找某个字符(正着找),找到了返回这个字符第一次出现的下标。找不到返回npos(定义在string里的一个静态常量;整型的最大值;-1的补码)。
cpp
int main() {
string s("oooxxx");//替换字符串中的某个文本
size_t pos = s.find('x');
while (pos != string::npos) {
s.replace(pos,1,1,'@');
pos = s.find('x',pos + 1);
}
cout << s << endl;
}
(6)rfind


和find功能相同,只是倒着找。
(7)pop_back

C++11引入了pop_back,用于尾删。
cpp
int main() {
string s("abcd");
s.pop_back();//尾删
cout << s << endl;//输出abc
}
(8)substr

从pos个位置往后截取len个长度,返回一个新的对象。
cpp
int main() {
string s1("abcdefgh");
string s2 = s1.substr(3, 3);//从s1的3个位置往后截取3个长度,返回一个新对象
cout << s2;
}
十、swap

交换两个对象中的内容。
cpp
int main() {
string s1("111111111");
cout << "交换前:s1=" << s1 << endl;
string s2("222222222");
cout << "交换前:s2=" << s2 << endl;
swap(s1, s2);
cout << "交换后:s1=" << s1 << endl;
cout << "交换后:s2=" << s2 << endl;
}

十一、getline
grtline是全局函数,它的声明被写在string.h里。用于解决cin的读取问题。(cin------从键盘读取数据,cout------在console写内容)
cin遇到空格和回车就会停止读取,后面的内容全部留在缓冲区里。getline用于处理cin读不到空格后面的问题。cin.ignore()用于忽略缓冲区的一个字符(cin留下的空格)。
cpp
int main() {
string s;
cout << "请输入:";
cin >> s;
cout << "cin读取到的数据:" << s << endl;//输出空格前内容
cin.ignore();//清理缓存区的空格
getline(cin, s);//解决cin遗留问题
cout << "getline读取到的数据:" << s << endl;//输出空格后内容
}
