C++——string(上)

一、基本概念

(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;//输出空格后内容
}

相关推荐
wljy12 小时前
第十三届蓝桥杯大赛软件赛省赛C/C++ 大学 B 组(个人见解,已完结)
c语言·c++·算法·蓝桥杯·stl
chushiyunen2 小时前
python pygame实现贪食蛇
开发语言·python·pygame
身如柳絮随风扬2 小时前
Lambda、方法引用与Stream流完全指南
java·开发语言
jinanwuhuaguo3 小时前
人工智能的进化阶梯:AI、ANI、AGI与ASI的核心区别与深度剖析
开发语言·人工智能·agi·openclaw
清空mega3 小时前
C++中关于数学的一些语法回忆(2)
开发语言·c++·算法
想唱rap3 小时前
线程池以及读写问题
服务器·数据库·c++·mysql·ubuntu
Mr_Xuhhh3 小时前
从理论到实践:深入理解算法的时间与空间复杂度
java·开发语言·算法
望眼欲穿的程序猿3 小时前
Vscode Clangd 无法索引 C++17 或者以上标准
java·c++·vscode
Lenyiin3 小时前
《Python 修炼全景指南:一》从环境搭建到第一个程序
开发语言·python