做网站的相关教程,深圳网页设计培训费用,上海网站开发外包公司,wordpress 网校文章目录 1. STL导读1. 1 什么是STL1. 2 STL的版本1. 3 STL六大组件1. 4 STL的重要性1. 5 STL的学习1. 6 STL系列博客的规划 2. string2. 1 为什么学习string类?2. 2 标准库中的string2. 3 基本构造2. 4 尾插与输出运算符重载2. 5 构造函数2. 6 赋值运算符重载2. 7 容量操作2.… 文章目录 1. STL导读1. 1 什么是STL1. 2 STL的版本1. 3 STL六大组件1. 4 STL的重要性1. 5 STL的学习1. 6 STL系列博客的规划 2. string2. 1 为什么学习string类?2. 2 标准库中的string2. 3 基本构造2. 4 尾插与输出运算符重载2. 5 构造函数2. 6 赋值运算符重载2. 7 容量操作2. 8 元素访问2. 9 迭代器2. 10 修改2. 11 字符串操作2. 12 不在类中的函数重载 3. 尾声 1. STL导读
1. 1 什么是STL
STL(standard template libaray-标准模板库):是C标准库的重要组成部分不仅是一个可复用的组件库而且是一个包罗数据结构与算法的软件框架。
1. 2 STL的版本
原始版本 Alexander Stepanov、Meng Lee 在惠普实验室完成的原始版本本着开源精神他们声明允许任何人任意运用、拷贝、修改、传播、商业使用这些代码无需付费。唯一的条件就是也需要向原始版本一样做开源使用。 HP 版本–所有STL实现版本的始祖。P.J. 版本 由P.J.Plauger开发继承自HP版本被Windows Visual C采用不能公开或修改缺陷可读性比较低符号命名比较怪异。RW版本 由Rouge Wage公司开发继承自HP版本被C Builder 采用不能公开或修改可读性一般。SGI版本 由Silicon Graphics Computer systems,inc公司开发继承自HP版本。被GCC(Linuxdevc等)采用可移植性好可公开、修改甚至贩卖从命名风格和编程风格上看阅读性非常高。学习STL时需要阅读的源代码主要参考的就是这个版本。
1. 3 STL六大组件 顺带一提string并不是STL标准所规定的容器实际上string的出现比STL早可以说是STL容器标准制作的探路石因此相对其它容器string的接口显得较为臃肿命名风格较为奇特但这并不妨碍它的强大。
1. 4 STL的重要性
在C入门基础介绍上这篇博客中我提到过C的第一个正式版本的颁布曾因为STL的出现而延误 C的标准化工作于1989年开始并成立了一个ANSI和IS0International StandardsOrganization国际标准化组织的联合标准化委员会。1994年标准化委员会提出了第一个标准化草案。在该草案中委员会在保持斯特劳斯特卢普最初定义的所有特征的时还增加了部分新特征。 在完成C标准化的第一个草案后不久STLStandard Template Library诞生了STL是惠普实验室开发的一系软件的统称。它是由Alexander Stepanov、MengLee和David RMusser在惠普实验室工作时所开发出来的。在通过了标准化第一个草案之后联合标准化委员会又投票并通过了将STL包含到C标准中的提议。STL对C的扩展超出C的最初定义范围。虽然在标准中增加STL是个很重要的决定但也因此延缓了C标准化的进程。 1997年11月14日联合标准化委员会通过了该标准的最终草案。1998年C的ANSI/IS0标准被投入使用。 接近三年的等待足以让任何人认识到它的重要性。 事实上也确实如此且功利地说一说在任何招聘C开发岗位的笔试与面试的题目中STL永远不会缺席而在实际的开发中STL也是贯穿整个C项目的根脉。 网上有句话说:“不懂STL不要说你会C”。STL是C中的优秀作品有了它许多底层的数据结构以及算法都不需要自己重新造轮子只有站在前人的肩膀上才能健步如飞的快速开发。
1. 5 STL的学习
以下来自侯捷老师的《STL源码剖析》 再功利地说在找工作之前一定要达到第二境界而在工作中慢慢地到达第三境界。 扩充STL不是任何人可以直接传授的道理而是一种慢慢沉淀出来的经验作为初学者不要盲目地尝试因为那大概率只是浪费时间。
1. 6 STL系列博客的规划
STL是一系列十分标准接口命名与使用都十分规范的标准库在本系列博客中将以容器和配接器的使用与模拟实现为主线在其中穿插算法仿函数以及迭代器。 容器的接口使用其实是十分相似的因此本系列博客会着重于容器的模拟实现仅在string时会详细介绍几乎所有接口其它的容器只会介绍与string差异较大的接口。
2. string
2. 1 为什么学习string类?
C语言中的字符串是以\0结尾的一些字符的集合为了操作方便C标准库中提供了一些字符串的库函数但是这些库函数与字符串是分离开的不太符合OOP面向对象程序设计的思想而且底层空间需要用户自己管理稍不留神可能还会越界访问。 而string——对字符串的封装可以很好地解决这一问题接口会自动向字符串的尾部添加\0不用自己操心\0也不需要担心越界访问一般情况下这使得无论是在OJ题还是实际开发中都很少有人会使用C语言的字符串。
2. 2 标准库中的string
string类被包含在string的头文件中同时也在std这个命名空间中。
2. 3 基本构造
string 类的成员其实和数据结构初阶中的顺序表是基本一样的都是一个数组只不过在 string 类中固定为char了有一个指针_size变量存储 string 中目前的数据个数_capacity存储 string 中指针的容量。
class string
{
private:char* _str;size_t _capacity;size_t _size;
};2. 4 尾插与输出运算符重载
为了方便后文展示构造函数方便先把这两个接口讲解一下。
尾插 在STL库中除了栈和队列这样的只能尾插或者说是入队列和入栈的容器之外所有容器的尾插都是以push_back命名的在 string 中就是
void push_back (char c);输出运算符重载
ostream operator (ostream os, const string str);string 并不是字符串所以正常情况下不能直接通过输出运算符输出但 string 类中对输出运算符进行了重载使得其可以直接进行输出。 使用范例
#includestring
#includeiostream
using namespace std;
int main()
{string s; //创建一个空的string实例化对象s.push_back(a);s.push_back(b);s.push_back(c);s.push_back(d);s.push_back(e);s.push_back(f);s.push_back(g);cout s;return 0;
}输出
2. 5 构造函数
库函数的容器都提供了非常多种构造函数以让使用更方便而在C98中 string 提供了七种初始化方式在C11中扩充至九种但多出来的两种其中一种涉及右值引用本文不作讲解另一种这里只介绍用法不介绍原理。
default 常用
string();不传任何参数的构造函数理所应当的创建的是一个没有存储任何数据的空 string。 用法
#includestring
using namespace std;
int main()
{string s;return 0;
}这个 string 实例化对象 s 中的_size是0但其容量不一定是零。
copy 常用
string (const string str);拷贝构造借助另一个 string 的实例化对象拷贝构造出一个新的实例化对象。
#includestring
#includeiostream
using namespace std;
int main()
{string s;s.push_back(a);s.push_back(b);s.push_back(c);cout s endl;string s1(s);cout s endl;string s2 s;cout s2 endl;return 0;
}
s1和s2在构造时都会以s为数据来源进行拷贝构造。 输出
from c-string常用
string (const char* s);从字符串中拷贝数据进行构造。 指针 s 指向的是一个字符串无论是常量字符串还是字符数组都必须以\0结尾才能保证正常构造。
#includestring
#includeiostream
using namespace std;
int main()
{char str[] Hello World!;string s(str);cout str endl s endl;return 0;
}输出
substring
string (const string str, size_t pos, size_t len npos);从 str 这个实例化对象中从 pos 位置下标开始拷贝走 len 个数据。
#includestring
#includeiostream
using namespace std;
int main()
{string s(Hello World!);string s1(s, 1, 6);cout s1;return 0;
}运行结果
from buffer
string (const char* s, size_t n);根据字符串 s 的前 n 位构造出一个 string 实例化对象。 使用
#includestring
#includeiostream
using namespace std;
int main()
{char str[] Hello World!;string s(str, 5);cout s endl;return 0;
}输出
fill 常用
string (size_t n, char c);构造出存储了 n 个元素 c 的实例化对象。
#includestring
#includeiostream
using namespace std;
int main()
{string s(10, a);cout s;return 0;
}输出
range 常用
template class InputIteratorstring (InputIterator first, InputIterator last);实际上是使用迭代器来构造对象。 迭代器是STL中一个十分重要的组件对于 string 来说它的迭代器就是对指针的封装需要在介绍begin()和end()接口之后才能使用。
initializer_list
string (initializer_listchar il);这里的initializer_list也是一种容器关于它的具体说明会在vector的相关博客中讲解这里只介绍其使用
#includestring
#includeiostream
using namespace std;
int main()
{string s({ 1,2,a,b });cout s endl;return 0;
}在创建实例化对象时在对象名后面的括号中加上一对大括号在其中写上一系列元素注意对于 string这里的元素必须是char类型的并以逗号隔开。 输出
2. 6 赋值运算符重载
因为赋值运算符重载和构造函数重合度较高所以放在一起讲解。 C11中 string 有5种赋值运算符重载因为其中一种涉及右值引用这里不做介绍。
拷贝赋值
string operator (const string str);其使用和拷贝构造其实差不多只是拷贝构造是在创建实例化对象时调用而拷贝赋值是对一个已经实例化的对象的操作。
#includestring
#includeiostream
using namespace std;
int main()
{string s(hello world);string s1(x);cout s1 endl;s1 s;cout s1 endl;return 0;
}输出
c-string
string operator (const char* s);和构造函数中的from c-string一样略。
character
string operator (char c);和c string是一样的只是从字符串变成了字符用于一些场景下的兼容。
#includestring
#includeiostream
using namespace std;
int main()
{string s(Hello World!);s a;cout s;return 0;
}输出
initializer_list
string operator (initializer_listchar il);和构造函数里的 initializer_list 是一样的略。
2. 7 容量操作
容量操作指对 string 对象中的_capacity和_size进行访问或操作的接口。
size()和capacity()重要 这两个接口根据它们的名称就可以推断出分别是返回_size和_capacity的大小。
size_t size() const;
size_t capacity() const;
//注省略了关于异常的关键字现阶段不用在意在一些情况下可能需要在类外面访问 string 对象的大小和容量比如对 string 进行下标遍历size()的大小就可以作为遍历次数。 不能直接访问对象中的 _size 和_capacity一方面是因为这是私有成员变量另一方面就算声明了友元函数C标准中并没有规定_size和_capacity的具体名称因此不同编译器中的这两个变量的名称可能不同如果直接在代码中访问成员变量会使代码的可移植性变差。
length()和max_size()
这两个接口几乎没有什么用武之地。 size()与length()方法底层实现原理完全相同引入size()的原因是为了与其他容器的接口保持一致一般情况下基本都是用size()。 后者是返回 string 对象可以达到的最大长度这是由已知的系统或库实现限制推断出的字符串可以达到的最大潜在长度但不能保证对象能够达到该长度在达到该长度之前它仍然可能无法在任何时候分配存储。所以它没有意义。
clear() 清除对象中存储的所有元素即_size置为0。
#includestring
#includeiostream
using namespace std;
int main()
{string s(Hello World!);s.clear();cout s;return 0;
}可以发现代码没有任何输出。
resize()重要
// resize()
void resize (size_t n);
void resize (size_t n, char c);resize()是重新设置 string 对象的大小如果新的_size小于原来的就会直接将多余元素删除实际上就是加一个\0如果新的_size大于原来的会使用第二个参数 c 去填补这些位置如果没有第二个参数默认是\0。 如果新的_size大于原来的容量还会进行扩容。
#includestring
#includeiostream
using namespace std;
int main()
{string s(Hello World!);cout s.size() endl;s.resize(2 * s.size());cout s.size() s endl;s.resize(2 * s.size(), a);cout s.size() s endl;return 0;
}输出
reserve() 重要和shrink_to_fit()
void reserve (size_t n 0); //注意reserve()是有缺省值的reserve()的作用是将 string 对象的容量扩大到n以上具体是多少C标准没有规定。 如果n_capacity这个函数不会有任何动作。 这个接口的意义是减少扩容带来的损耗编译器在创建一个 string 实例化对象时并不知道它最终会存储多少数据因此使用过程中不可避免地需要扩容而我们知道扩容是有效率损耗的如果原来的地址后面的空间不足就需要拷贝原数据到新地址因此如果程序员已知 string 对象存储的最大值或是不低于某个值就可以直接reserve()一下以减少扩容。
而shrink_to_fit()是请求字符串减小其容量以适应其大小也就是释放没有存储数据的空间。 但是这个接口是非强制性的C标准只规定这个接口调用后对象的容量不低于其大小就可以了编译器可以在此基础上任意优化。
empty() 重要 返回对象是否为空即其长度是否为 0。
2. 8 元素访问
operator[]重载 重要 string 是对字符串的封装因此是无法直接使用下标访问操作符的必须通过操作符重载 char operator[] (size_t pos);
const char operator[] (size_t pos) const;其重载的返回值均为下标指向元素的引用只是如果对象被const修饰不可修改那么其返回的引用也不可修改。 下标访问操作符不会检查pos指向的位置是否合法如果 pos 大于对象的大小会发生未定义行为。 所有容器的元素访问操作符都会提供 const 版本以兼容对象被 const 修饰的情况。 at() at()与下标访问操作符几乎一样只是at()会检查pos位置是否合法如果非法就会抛出异常。 front()和back()
分别返回对象中第一个元素和最后一个元素的引用注意也会有 const 修饰的区别。
2. 9 迭代器
在 string 中可以把迭代器这样简单地理解
typedef char* interator;
typedef const char* const_interator; //注意const迭代器的写法用_相连当然现代的迭代器是对指针的进一步封装不过在早期string 的迭代器就是这样的所以我们可以先这么理解使用上是没有差别的。
auto 重要 auto关键字可以在创建变量自动识别其类型而无需显式写出在迭代器这里使用的非常频繁。 对于 string 来说它的迭代器类型为
std::string s;
// std::string::iterator it1 s.begin();
auto it1 s.begin();似乎也不是很长但是如果是将来的一个数据结构 map情况就不一样了
std::mapstd::string, std::string m;
// std::mapstd::string, std::string::iterator it2 m.begin();
auto it2 m.begin();不需要管这个类型具体是什么只需要知道这样写很麻烦而auto可以帮助我们省去这个麻烦就可以了。 比如
补充 在早期C/C中auto的含义是使用auto修饰的变量是具有自动存储器的局部变量但是后来这个东西变得不重要了。C11中标准委员会变废为宝赋予了auto全新的含义即auto不再是一个存储类型指示符而是作为一个新的类型指示符来指示编译器auto声明的变量必须由编译器在编译时期推导而得。用auto声明指针类型时用auto和auto*没有任何区别但用auto声明引用类型时则必须加当在同一行声明多个变量时这些变量必须是相同的类型否则编译器将会报错因为编译器实际只对第一个类型进行推导然后用推导出来的类型定义其他变量。auto不能作为函数的参数可以做返回值但是建议谨慎使用 。会降低代码可读性auto不能直接用来声明数组 begin()和end() 重要 这两个接口分别返回指向string对象第一个元素和最后一个元素的下一个位置的迭代器。 根据this指针是否被const修饰返回的迭代器类型也会改变。 正式因为end()指向的最后一个元素的下一个位置也就是说end()的返回值的解引用没有意义所以在使用迭代器区间进行构造/赋值时都是左闭右开的。 范围 for 重要 如果我们要使用迭代器遍历一个string对象原本应该是这样写的
#includeiostream
#includestring
using namespace std;
int main()
{string s(Hello World!);for (auto it1 s.begin(); it1 ! s.end(); it1){cout *it1 ;}return 0;
}当然这里有两点需要注意 在string类中迭代器可以直接当做指针进行解引用也可以进行±和自增自减的操作。 迭代器在遍历时结束条件最好不要写it1 s.end()因为其他容器的数据存储可能不是连续的写成it1 ! s.end()有助于代码风格的统一。
对于一个有范围的集合而言由程序员来说明循环的范围是多余的有时候还会容易犯错误。 因此C11中引入了基于范围的for循环。 for循环后的括号由冒号:分为两部分第一部分是范围内用于迭代的变量第二部分则表示被选代的范围自动迭代自动取数据自动判断结束。范围for可以作用到数组和容器对象上进行遍历范围for的底层很简单容器遍历实际就是替换为迭代器这个从汇编层也可以看到。
范围for不是 string 类的特权事实上只要类支持迭代器且命名为 iterator 和 const_iterator 就可以自动地支持范围for。 范围for的使用为
#includeiostream
#includestring
using namespace std;
int main()
{string s(Hello World!);for (auto i : s){cout i ;}return 0;
}这里也有两点要注意 用于迭代的变量的类型可以写成auto也可以显式地写出来。 如果不加引用符号范围 for 在遍历时会把容器中的元素直接复制给迭代变量迭代变量不是迭代器 因为默认情况下会发生复制如果迭代变量的类型不是基础变量而是类实例化对象可能会造成效率大幅降低因此我们可以使用引用来规避复制
for (auto i : s)
{cout i ;
}但是要注意如果容器没有被 const 修饰那么迭代变量 i 默认是可以修改数据的如果不希望 i 有修改的权限可以在 auto 前加一个 const
for (const auto i : s)
{cout i ;
}反向迭代器 除了上面说的两个迭代器之外 string 还支持反向迭代器类型为
reverse_iterator
const_reverse_iterator同时也有对应的rbegin()和rend()。 对于反向迭代器string中最后一个数据就是开始第一个数据是结束因此 rbegin() 和 rend() 返回的分别是指向数据末尾和数据开始的上一个位置的反向迭代器。 反向迭代器与指针有些差异但仍然可以进行解引用自增自减等操作只不过反向迭代器自增后会指向原来数据的上一个数据。
2. 10 修改
push_back() 前面已经介绍过了。略。append() C11中append有7中重载
//string (1)
string append (const string str);
//substring (2)
string append (const string str, size_t subpos, size_t sublen);
//c-string (3)
string append (const char* s);
//buffer (4)
string append (const char* s, size_t n);
//fill (5)
string append (size_t n, char c);
//range (6)
template class InputIteratorstring append (InputIterator first, InputIterator last);
//initializer list(7)
string append (initializer_listchar il);和构造函数有一些共通之处就不挨个解释了。 append() 的作用就是在原来字符串的后面追加元素如字符串等。
operator 重要 append() 有很多重载但是全部记下来似乎有些困难但是不要紧string 类重载了 运算符。
//string (1)
string operator (const string str);
//c-string (2)
string operator (const char* s);
//character (3)
string operator (char c);
//initializer list (4)
string operator (initializer_listchar il);operator 支持 append 中除了迭代器区间fillsubstring 之外的所有操作大部分情况下 operator 就可以应付了。
举例
#includeiostream
#includestring
using namespace std;
int main()
{string s(Hello World!);string s1(kkkk);s1 s;cout s1;return 0;
}输出 4. assign() 为 string 对象分配一个新值替换其当前内容。 其重载和构造函数也基本一致 // string (1)
string assign (const string str);
// substring (2)
string assign (const string str, size_t subpos, size_t sublen);
// c-string (3)
string assign (const char* s);
// buffer (4)
string assign (const char* s, size_t n);
// fill (5)
string assign (size_t n, char c);
// range (6)
template class InputIteratorstring assign (InputIterator first, InputIterator last);
// initializer list(7)
string assign (initializer_listchar il);使用起来的效果和先 clear() 再 append(xxx) 的效果是一样的。 可以当做内置类型的赋值运算符。
insert()和erase() C11中insert 可以插入的有
// string (1)
string insert (size_t pos, const string str);
// substring (2)
string insert (size_t pos, const string str, size_t subpos, size_t sublen);
// c-string (3)
string insert (size_t pos, const char* s);
// buffer (4)
string insert (size_t pos, const char* s, size_t n);
// fill (5)
string insert (size_t pos, size_t n, char c);
iterator insert (const_iterator p, size_t n, char c);
// single character (6)
iterator insert (const_iterator p, char c);
// range (7)
template class InputIteratoriterator insert (iterator p, InputIterator first, InputIterator last);
// initializer list (8)
string insert (const_iterator p, initializer_listchar il);在这些函数重载中有的使用的是数组下标的形式有的是迭代器不必刻意去记在需要的时候查一下再使用就可以了。 插入时可以看做是向这个迭代器/下标指向元素之前插入。
erase 有三个重载
// sequence (1)
// 从pos下标开始删除len个元素
string erase (size_t pos 0, size_t len npos);
// character (2)
// 删除迭代器指向的元素
iterator erase (const_iterator p);
// range (3)
// 删除first-last之间的所有元素注意左闭右开
iterator erase (const_iterator first, const_iterator last);swap() 重要 用于交换两个 string 对象。 使用
#includeiostream
#includestring
using namespace std;
int main()
{string s(Hello World!);string s1(kkkk);s.swap(s1);cout s1 s;return 0;
}需要注意的是在算法库algorithm中也有一个通用的swap函数
#includeiostream
#includestring
#includealgorithm
using namespace std;
int main()
{string s(Hello World!);string s1(kkkk);swap(s, s1); //调用方式不一样cout s1 s;return 0;
}虽然这两个 swap 的结果是一样的但是对于string来说应该尽可能使用 string 类的成员函数中的 swap这涉及到了深浅拷贝问题我会在下一篇博客——string类的模拟实现中详细介绍这一点。
replace() 这个函数使用较少自行参考cplusplus了解一下即可。
2. 11 字符串操作 c_str() 重要 返回一个指向数组的指针该数组包含以 null 结尾即’\0’的字符序列即 C 字符串表示 string 对象的当前值。 这个函数用于用于兼容一些string类没有实现的字符串的用法。 注意这个指针可能会在string对象调用一些接口后失效如扩容。 find()和rfind() find 用于在 string 对象中查找字符/字符串。
// string (1)
// 从pos位置开始查找与str相同的字符串返回第一个元素的下标如果没找到会返回string::npos-1
size_t find (const string str, size_t pos 0) const noexcept;
// c-string (2)
// 和上面的相同只是从string变成了字符串
size_t find (const char* s, size_t pos 0) const;
// buffer (3)
// 与2相同只是只匹配s的前n个字符
size_t find (const char* s, size_t pos, size_type n) const;
// character (4)
// 从pos位置开始查找字符 c
size_t find (char c, size_t pos 0) const noexcept;find是从前往后查找而rfind是从后往前查找。 e.g.使用find()找出字符串中所有’c’的下标
#includeiostream
#includestring
using namespace std;
int main()
{string s(Heclcloc Wcorld!c);size_t pos s.find(c);while (pos ! string::npos){cout pos ;pos; //注意要一次不然会死循环pos s.find(c, pos);}return 0;
}find_first_of() 在字符串中搜索与其参数中指定的任何字符匹配的第一个字符。
// string (1)
// 从pos位置开始找与str中任意一个字符相同的字符
size_t find_first_of (const string str, size_t pos 0) const noexcept;
// c-string (2)
size_t find_first_of (const char* s, size_t pos 0) const;
// buffer (3)
// 只匹配s的前n个字符
size_t find_first_of (const char* s, size_t pos, size_t n) const;
// character (4)
size_t find_first_of (char c, size_t pos 0) const noexcept;与之对应的还有一组接口
find_first_of()
// Find character in string (public member function )
find_last_of()
// Find character in string from the end (public member function )
find_first_not_of()
// Find absence of character in string (public member function )
find_last_not_of()
// Find non-matching character in string from the end (public member function )compare() 比较函数。
// string (1)
//比较this和str是否相同
int compare (const string str) const noexcept;
// substrings (2)
// 比较区间pos,len给this,subpos和sublen给str
int compare (size_t pos, size_t len, const string str) const;
int compare (size_t pos, size_t len, const string str,size_t subpos, size_t sublen) const;
// c-string (3)
int compare (const char* s) const;
int compare (size_t pos, size_t len, const char* s) const;
// buffer (4)
int compare (size_t pos, size_t len, const char* s, size_t n) const;返回值
valuerelation between compared string and comparing string0They compare equal0Either the value of the first character that does not match is lower in the compared string, or all compared characters match but the compared string is shorter.0Either the value of the first character that does not match is greater in the compared string, or all compared characters match but the compared string is longer.
2. 12 不在类中的函数重载
operator和operator 重要
istream operator (istream is, string str);
ostream operator (ostream os, const string str);istream和ostream分别是cin和cout的类型。 这两个重载使得 string 可以直接输入输出而不需要借助字符串。 使用
#includeiostream
#includestring
using namespace std;
int main()
{string s;cin s;cout s;return 0;
}输入与输出
operator
可以通过operator类比只是不会修改 this 指针而是直接返回相加后的值。 一般来讲不推荐使用因为这个函数是传值返回需要进行深拷贝效率低。
getline() 重要 我们时常会需要输入一个带有空格的字符串在C语言中带有空格的字符串只能通过循环调用getchar()来实现但在 C 中提供了getline函数来解决这一问题。
istream getline (istream is, string str, char delim);
istream getline (istream is, string str);istream 是 cin 的类型第一个参数可以传 cin第二个参数传 string 对象第三个参数可以指定输入的停止符默认是\n也就是在默认情况下getline 会读取一行输入无论是否带有空格。 使用
#includeiostream
#includestring
using namespace std;
int main()
{string s;getline(cin, s);cout s;return 0;
}输入输出
3. 尾声
其实对于STL来说它们的接口并不需要死记硬背并且大概率也背不下来。 只需要在最开始的时候了解一遍在需要的时候如果不记得了就可以在cplusplus上查一下用的多了自然而然就记住了记不住就说明这个接口/重载不重要不需要死磕。
谢谢你的阅读喜欢的话来个点赞收藏评论关注吧 我会持续更新更多优质文章