目录
[1.2 自动内存管理](#1.2 自动内存管理)
[1.3. 安全性更高](#1.3. 安全性更高)
[1.4. 提供丰富的成员函数](#1.4. 提供丰富的成员函数)
[1.5. 支持面向对象编程](#1.5. 支持面向对象编程)
[3.1 auto关键字---自动识别变量类型](#3.1 auto关键字---自动识别变量类型)
[3.2 范围for](#3.2 范围for)
[4.1 构造函数](#4.1 构造函数)
[4.2 迭代器(iterator)](#4.2 迭代器(iterator))
[4.3. string类对象的容量操作](#4.3. string类对象的容量操作)
[4.5 string类对象的修改操作](#4.5 string类对象的修改操作)
[4.6. string类非成员函数](#4.6. string类非成员函数)
一、为什么c++引入了string类
C++ 设计string
类是为了提供一种更方便、更安全、更强大的字符串处理方式,相比于c风格的字符串,string类的优势在于:
1.1简化字符串操作
C 风格字符串操作复杂 :在 C 语言中,字符串是用字符数组来表示的,以空字符'\0'结尾。对字符串进行操作时,往往需要手动管理内存和处理边界条件,代码较为繁琐。
string
类操作简单 :C++ 的string
类封装了这些操作,提供了直观的运算符重载和成员函数,使得字符串操作更加简洁。
1.2 自动内存管理
C 风格字符串内存管理困难 :使用 C 风格字符串时,需要手动分配和释放内存。如果分配的内存不足,会导致缓冲区溢出;如果忘记释放内存,会造成内存泄漏。
string
类自动管理内存 :string
类会自动处理内存的分配和释放,用户无需手动管理。当string
对象的大小发生变化时,它会自动调整内部缓冲区的大小。
1.3. 安全性更高
C 风格字符串容易出现缓冲区溢出 :由于 C 风格字符串不记录自身长度,使用strcpy
、strcat
等函数时,如果目标数组空间不足,会导致缓冲区溢出,从而引发安全问题。
string
类避免缓冲区溢出 :string
类会自动处理字符串的长度,不会出现缓冲区溢出的问题。当进行字符串操作时,string
类会确保内部缓冲区有足够的空间。
1.4. 提供丰富的成员函数
string
类提供了大量实用的成员函数:如查找子串、替换子串、截取子串等,方便进行各种字符串处理。
1.5. 支持面向对象编程
string
类符合面向对象编程的思想 :可以将string
对象作为类的成员变量,也可以在函数之间传递string
对象,方便进行模块化编程和代码复用。
二、标准库中的string类
string的文档介绍:cplusplus.com/reference/string/string/?kw=string
标准string类具有类似于标准字节容器的接口,并且具有专门设计的用于操作单字节字符串的特性
三、补充:auto与范围for
3.1 auto关键字---自动识别变量类型
在早期C/C++中auto的含义是:使用auto修饰的变量,是具有自动存储器的局部变量,后来这个不重要了。C++11中,标准委员会变废为宝赋予了auto全新的含义即:auto不再是一个存储类型指示符,而是作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期
推导而得。
(1)用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须加&
当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际
只对第一个类型进行推导,然后用推导出来的类型定义其他变量。
(2)auto不能作为函数的参数,可以做返回值,但是建议谨慎使用.
(3)auto不能直接用来声明数组
结合代码加深理解:
cpp
#include<iostream>
using namespace std;
int main() {
int a = 6;
//auto能够自动识别变量类型,无须具体指出,根据初始化的类型自动进行推导
auto b = a;
//auto修饰的变量必须初始化
//auto c; // error:无法推导"auto"类型
int* p = &a;
//推导指针变量时,可以用auto,也可以用auto*
auto* d = p;
auto e = p;
//但是使用auto*时,推导的变量必须是指针变量
//auto* e = a;// error:无法推导"auto"类型
long double x = 0;
//auto常用修饰简化一个很长的类型名
auto w = x;
return 0;
}
3.2 范围for
对于一个有范围的集合而言,由程序员来说明循环的范围是多余的,有时候还会容易犯错误。因此C++11中引入了基于范围的for循环。for循环后的括号由冒号" :"分为两部分:第一部分是范围内用于迭代的变量,第二部分则表示被迭代的范围,自动迭代,自动取数据,自动判断结束。
范围for可以作用到数组和容器对象上进行遍历
结合代码加深理解:
cpp
#include<iostream>
using namespace std;
int main() {
int arr[] = { 2,5,1,4,5,99,8,0,5 };
//使用范围for进行数组的遍历
for (int e : arr) {
cout << e << " ";
}
cout << endl;
return 0;
}
四、string类的常用接口
在学习string类时,我们会借助官方文档进行学习,在学习string类的过程中逐步掌握浏览文档的方式。
注意需要包含头文件<string>,同时使用命名空间std;
4.1 构造函数

重点掌握默认构造,拷贝构造,带参构造

cpp
#include<iostream>
#include <string>
using namespace std;
int main() {
string s1;//默认构造
string s2("hello world");//带参构造
string s3(s2);//拷贝构造
cout << s2 << endl << s3 << endl;
return 0;
}
注意:(3)中的npos代表无符号整数的最大值,是一个很大的数
4.2 迭代器(iterator)

begin:返回起始位置,end:返回字符串末尾\0所在位置。注意在使用begin()与end()时,所指向的范围区间是"左闭右开"的,而rbegin和rend则是反过来的begin和end,代码演示如下:
cpp
#include<iostream>
#include<string>
using namespace std;
int main() {
string s1("hello world");
string::iterator it1 = s1.begin();
string::iterator it2 = s1.end();
cout << *it1 << " "<< *(it2 - 1);
return 0;
}
4.3. string类对象的容量操作

结合代码:
cpp
#include<iostream>
#include<string>
using namespace std;
int main() {
string s3("this is an apple");
//s3的最大空间
cout << s3.capacity() << endl;
//s3的有效字符个数,不包括\0
cout << s3.size() << endl;
//重新设置s3的size大小
//resize(x):
//当x < size,删除数据,capacity不变;
//当x> size 且x < capacity,往字符串中插入数据,默认是\0
//当x > capacity,扩容
s3.resize(10);
cout << s3 << endl;
//empty判断字符串是否为空串,不是空返回0,为空返回1
bool em1 = s3.empty();
cout << em1 << endl;
s3.clear();
bool em2 = s3.empty();
cout << em2 << endl;
cout << s3.size() << endl;
//reserve 直接申请所需的空间,不会修改内容,即size不会因此改变
s3.reserve(65);
cout << s3.size() << endl;
cout << s3.capacity() << endl;
return 0;
}
注意:
-
size()与length()方法底层实现原理完全相同,引入size()的原因是为了与其他容器的接口保持一致,一般情况下基本都是用size()。
-
clear()只是将string中有效字符清空,不改变底层空间大小。
-
resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不同的是当字符个数增多时:resize(n)用0来填充多出的元素空间,resize(size_t n, char c)用字符c来填充多出的元素空间。注意:resize在改变元素个数时,如果是将元素个数增多,可能会改变底层容量的大小,如果是将元素个数减少,底层空间总大小不变。
-
reserve(size_t res_arg=0):为string预留空间,不改变有效元素个数,当reserve的参数小于string的底层空间总大小时,reserver不会改变容量大小。
4.4.string类对象的访问及遍历操作

cpp
#include<iostream>
#include<string>
using namespace std;
int main() {
string s5("today is Saturday");
//使用operator[]来访问
for (int i = 0; i < s5.size(); i++) {
cout << s5[i];
}
cout << endl;
//使用iterator begin + end 来访问
string::iterator it = s5.begin();
while (it != s5.end()) {
cout << *it;
it++;
}
cout << endl;
//使用iterator rbgin + rend 来访问---逆转顺序
string::reverse_iterator it2 = s5.rbegin();
while (it2 != s5.rend()) {
cout << *it2;
it2++;
}
cout << endl;
return 0;
}
4.5 string类对象的修改操作

注:由于c语言中没有string类,为了兼容c语言,c++的string类中设置了c_str的接口,其返回值是一个指向字符串的指针,这个指针可读不可改,在使用之前需要先转化,一定要使用strcpy()
等函数来操作c_str()
返回的指针。
cpp
#include<iostream>
#include<string>
using namespace std;
int main() {
string s6("there");
cout << s6 << endl;
//追加单个字符
s6 += '!';
cout << s6 << endl;
//追加字符串
s6 += "is";
cout << s6 << endl;
//追加一个string类
string s7 = " an apple";
s6 += s7;
cout << s6 << endl;
//使用c_str,返回的是一个const char*指针
/*char* c;
string s = "1234";
c = s.c_str();*/
//error:不能将 "const char *" 类型的值分配到 "char *" 类型的实体
return 0;
}
4.6. string类非成员函数

注:在cin与scanf中,都会将空格字符与换行字符作为分隔,无法获取到,而使用getline则可以解决这一问题,还可以指定想要的分隔符
cpp
#include <iostream>
#include <string>
using namespace std;
int main()
{
string name;
string name2;
cout << "Please, enter your full name: ";
//此时默认以换行符作为结束
getline(cin, name);
cout << "Hello, " << name << "!\n";
cout << "Please, enter your full name2: ";
//此时将以给定的字符"!"作为结束
getline(cin, name2,'!');
cout << "Hello, " << name2 << "!\n";
return 0;
}
完
创作不易,感谢三连支持!