目录
0.引言
1. 字符串是表示字符序列的类
2. 标准的字符串类提供了对此类对象的支持,其接口类似于标准字符容器的接口,但添加了专门用于操作单字节字符字符串的设计特性。
3. string 类是使用 char( 即作为它的字符类型,使用它的默认 char_traits 和分配器类型 ( 关于模板的更多信息,请参阅basic_string) 。
4. string 类是 basic_string 模板类的一个实例,它使用 char 来实例化 basic_string 模板类,并用 char_traits和allocator 作为 basic_string 的默认参数 ( 根于更多的模板信息请参考 basic_string) 。
5. 注意,这个类独立于所使用的编码来处理字节 : 如果用来处理多字节或变长字符 ( 如 UTF-8) 的序列,这个类的所有成员( 如长度或大小 ) 以及它的迭代器,将仍然按照字节 ( 而不是实际编码的字符 ) 来操作。
总结:1.我们用string定义字符串类变量
2.string包含的头文件是#include<string>
3.string是属于std命名空间的,using namespace std;
4.string类是管理动态增长字符数组,这个字符串以\0结尾。
1.STL介绍
标准模板库(Standard Template Library,STL)是惠普实验室开发的一系列软件的统称。STL的代码从广义上讲分为三类:algorithm(算法)、container(容器)和iterator(迭代器),几乎所有的代码都采用了模板类和模板函数的方式,这相比于传统的由函数和类组成的库来说提供了更好的代码重用机会。
STL细分为六大组件:
今天我们要讲的就是STL库中的容器中的string.
2.string类对象构造
2.1string类成员函数
构造函数类:
1.无参构造string()
string s1;
2.带参构造string(const char* s);
string s2("hehe");//常量字符串初始化
3.拷贝构造string(const string& str);
string s2=("hehe"); string s3(s2); //拷贝构造 string s4=s2; //拷贝构造
4.对一个字符串的前n个初始化string (const char* s, size_t n)
string s5("https://mp.youkuaiyun.com/mp_blog", 7);//对该字符串的前5个初始化 cout << s5 << endl; // https:/
5.将字符c复制n次string(size_t n, char c)
string s6(5, 'k');//用5个k初始化 cout << s6 << endl;//kkkkk
6.拷贝s中从pos位置起的len个字符,若npos>字符串长度,就拷贝到字符串结尾结束string(const string& str, size_t pos, size_t len = npos);string s7("https:mp.youkuaiyun.com");//带参拷贝构造 string s8(s7, 6, 5);//从s7字符串的第6个位置往后取5个字符初始化 cout << s8 << endl;// 打印mp.cs
2.2析构函数
前面已经说过string类是管理动态增长字符数组,对于动态申请的空间,需要用到析构函数把它释放掉。不过这里我们无需操作,因为编译器会帮我们默认调用构造函数。
2.3operate=(赋值)
(各位同学有兴趣可以去cplusplus官网去查) 。
3.string一些容量成员
3.1成员介绍
size:返回有效字符个数
size_t size() const;
length:返回有效字符个数
(length和size其实功能一样,但是size更贴切,所以其他容量都有size,但不一定有length)
size_t length() const;
max_size:返回最大值
size_t max_size() const;
resize:调整字符串大小
void resize (size_t n); void resize (size_t n, char c);
capacity:返回的是容量大小
size_t capacity() const;
reserve:更改容量的
size_t reserve() const;
void clear();
empty:测试字符串是否为空
bool empty() const;
3.2成员函数代码测试
3.21reverse和resize
reserve的特性:
1.请求将字符串容量适应计划的大小更改为最多 n 个字符的长度。
2.如果 n 大于当前字符串容量,则该函数会导致容器将其容量增加到 n 个字符(或更大)。
3.在所有其他情况下,它被视为收缩字符串容量的非约束性请求:容器实现可以自由地进行优化,并使字符串的容量大于n。
4.此函数对字符串长度没有影响,并且无法更改其内容。
5.利用reserve进行提前预留空间,可以减少扩容带来的损耗。void test4() { string s("I love C++"); cout << s << endl; //I love C++ cout << s.size() << endl; //10 cout << s.capacity() << endl; //15 //reverse(n)当n大于对象当前的capacity时,将当前对象的capacity扩大为n或大于n s.reserve(20); cout << s << endl; //I love C++ cout << s.size() << endl; //10 cout << s.capacity() << endl; //31 //reverse(n)当n小于对象当前的capacity时,什么也不做 s.reserve(5); cout << s << endl; // cout << s << endl; //I love C++ cout << s.size() << endl; //10 cout << s.capacity() << endl; //31 } int main() { test4(); }
resize的特性:
1. 将字符串大小调整为 n 个字符的长度。
2. 如果 n 小于当前字符串长度,则当前值将缩短为其前 n 个字符,并删除超出第 n 个字符的字符。
3. 如果 n 大于当前字符串长度,则通过在末尾插入所需数量的字符以达到 n 大小来扩展当前内容。如果指定了 c,则新元素将初始化为 c 的副本,否则,它们是值初始化字符(空字符)。void test5() { string s1("I love C++"); //resize(n)n小于对象当前的size时,将size缩小到n s1.resize(4); cout << s1 << endl; // I lo cout << s1.size() << endl; //4 cout << s1.capacity() << endl; //15 string s2("I love C++"); //resize(n)n大于对象当前的size时,将size扩大到n,扩大的字符默认为'\0' s2.resize(20); cout << s2 << endl; //I love C++ cout << s2.size() << endl; //20 cout << s2.capacity() << endl; //31 string s3("I love C++"); //resize(n, char)n大于对象当前的size时,将size扩大到n,扩大的字符为char s3.resize(20, 'y'); cout << s3 << endl; //I love C++yyyyyyyyyy cout << s3.size() << endl; //20 cout << s3.capacity() << endl; //31 } int main() { test5(); }
其中void resize (size_t n, char c)说一下
先开辟空间,然后空间大于所写字符串的话用c(char c)来补全其余空间。
两者区别:
1.
reserve(): serve 是“保留”的词根,所以是用来预留容量的,并不会改变容器的有效元素个数。即用reserve()开辟空间时,仅改变capacity大小,与size无关。
resize(): size 是“大小”的意思,它主要用来调整容器有效元素的个数,有时候也会造成容量的改变。因此用resize()开辟空间时,会对增加的空间全部进行初始化,使得有效元素个数增加。2.
如果当前字符量小于n, reverse()对剩余容量不做处理,resize()则需要插入一些元素直到空间补满。
3.
两个概念:
容量(capacity): 指容器在自由内存中获得存储空间的大小,容量为100时并不代表有100个元素,可能有效元素只有10个,剩下的90个都是闲置的未定义的内存空间。
大小(size): 指的是容器中实际(有效)元素的个数,当大小为100时,就代表容器中已存在100个元素,容量一定不小于100。3.22clear和empty
名字就是他们对应的功能清理和判空
void test() { string s("hello world"); cout << s << endl;//hello world s.clear();//清空有效字符 if (s.empty()) cout << "empty" << endl;//empty }
4.迭代器
4.1迭代器介绍
迭代器是一个变量,相当于容器和操纵容器的算法之间的中介。迭代器可以指向容器中的某个元素,通过迭代器就可以读写它指向的元素。从这一点上看,迭代器和指针类似。
迭代器按照定义分为以下四种:正向迭代器 : --容器类名:iterator 迭代器名;
常量正向迭代器 : -- 容器类名::const_iterator 迭代器名;
反向迭代器 : --容器类名::reverse_iterator 迭代器名;
常量反向迭代器 : --容器类名::const_reverse_iterator 迭代器名;
例如:
#include <iostream> #include <vector> using namespace std; int main() { vector<int> v; //v是存放int类型变量的可变长数组,开始时没有元素 for (int n = 0; n<5; ++n) v.push_back(n); //push_back成员函数在vector容器尾部添加一个元素 vector<int>::iterator i; //定义正向迭代器 for (i = v.begin(); i != v.end(); ++i) { //用迭代器遍历容器 cout << *i << " "; //*i 就是迭代器i指向的元素 *i *= 2; //每个元素变为原来的2倍 } cout << endl; //用反向迭代器遍历容器 for (vector<int>::reverse_iterator j = v.rbegin(); j != v.rend(); ++j) cout << *j << " "; return 0; }
这个vector和string都可以看做一个容器。两者用法基本一致。其中用到的函数。
接下来我们写一个字符串类型的。
而逆向迭代器是从后往前遍历的,只不过迭代器名字叫reverse_iterator(reverse是反向的意思,跟上面的reserve别搞混了)。
void test1() { string s2("iterator is very beautiful"); string::reverse_iterator j = s2.rbegin(); while (j != s2.rend()) { cout << *j << " "; j++; } }
补充:const正向迭代器和const反向迭代器
为加上const一图就报错了
因为刚开始迭代器是可读可写的,但是加上onst权限就缩小了,str就不能写了。拿我们也要缩小相应的权限了。
反向迭代器和正向的操作一样(const_reverse_iterator)。
5.string中的元素访问
operate[]获取pos处的字符
返回对字符串pos位置处的字符引用。
一般就用下标+[]访问某位置字符。
6.string类对对象的修改操作
数据结构中对于链表和顺序表,我们学习了增删查改等操作,string类也是一块连续的地址,我们也能进行相应操作。
接下来让我们一一介绍
1.push_back字符串尾进行插入(尾插)
void push_back (char c);
2.insert指定位置插入
void test5() { string str("hello world"); //头部插入一个字符: str.insert(0, 1, 'x'); cout << str << endl; //xhello world //头部插入两个个字符: str.insert(0, 2, 'x'); //xxxhello world cout << str << endl; //xhello world } int main() { test5(); }
iinsert有三个参数,0是指在下标是0处进行插入,1是插入1个字符,x是插入一个字符x,
就比如下面这个,xhello world再在0处插入两个x,所以是xxx....。
迭代器也可以进行该操作
void test5() { string str("I love C++"); cout << str << endl; string::iterator it = str.begin(); str.insert(it, 1, 'y'); cout << str << endl; //yI love C++ //在第n个位置插入字符: str.insert(3, 1, 'x'); cout << str << endl; //yI xlove C++ str.insert(str.begin() + 3, 1, 'k'); cout << str << endl; //yI kxlove C++ //头插一个字符串: str.insert(0, "!!!!"); cout << str << endl; //!!!!yI kxlove C++ } int main() { test5(); }
3.append在字符串尾部追加字符串(也可以是单个字符)
void test6() { string str1("I love "); string str2("C"); str1.append(str2); cout << str1 << endl; //I love C //追加一个常量字符串 str1.append("++"); cout << str1 << endl; //I love C++ //用n个字符拼接 str1.append(3, '!'); cout << str1 << endl; //I love C++!!! } int main() { test6(); }
上面append一般有两种情况append(str2)追加字符串str2到str1上面
append(n, char ch) 在字符串尾部插入n个字符ch。
4.erase.擦除
void test7() { string str("I love C++"); //头删 str.erase(str.begin()); cout << str << endl; // " "love C++,特标一下空格 //头删指定字符: str.erase(str.begin() + 3); cout << str << endl; // loe C++ //从pos处位置删除n个字符: str.erase(2, 3); cout << str << endl; //lC++ //利用缺省值,只给定删除的位置,往后全删: str.erase(3); cout << str << endl; //lC str.erase(0); cout << str << endl; //空 } int main() { test7(); }
5.swap交换函数
void swap (string& str);
这个交换类型有点特殊,因为STL库里还有一个相同名称的非成员函数swap。
但是这个swap不需要加任何前缀直接使用。
void test8() { string str1("hehehe"); cout << str1 << endl; //hehehe string str2("wuwuwu"); //string类的成员函数 str1.swap(str2); cout << str1 << endl; //wuwuwu string str3("hello world"); //非类的成员函数 swap(str1, str3); cout << str1 << endl; //hello world } int main() { test8(); }
补充:string类的非成员函数getline(也可以理解为写入)(其他非成员函数一般用的比较少,就不过多介绍了)
既然都是写入那他和cin有啥区别?
getline: 按行读取, 一次读取多个字符,直到读满N个,或者遇到指定的结束符(自定义的或者EOF或者换行符,不包括空白符)为止。
形式:getline(字符指针,字符个数N,结束符);cin读取的话,遇到结束符(包括空白符)会终止,只读取空白符之前的部分。