2024年最全【C++】STL —,2024年最新我的华为面试经历分享

img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

}


下面两个函数功能一致,(at的存在有历史原因)只不过**二者检查越界的方式不同**,推荐使用`[]` ——


![在这里插入图片描述](https://img-blog.csdnimg.cn/85aaefcf61ff40d9bcfb63c686defb5c.png)


### 五、Capacity 容量操作


![在这里插入图片描述](https://img-blog.csdnimg.cn/839d5c134f774d8d99c4c471da797adb.png)


#### ⚡size vs length


➰字符串中**有效字符**长度,即不包含最后作为结尾标识符的`\0`


![在这里插入图片描述](https://img-blog.csdnimg.cn/fb7025fd89ab41d6bc3e7dfe3103fb39.png)


两者**底层实现完全一致**(length的存在是历史原因),但**强烈推荐**使用`size`. 这是为了和后序各种容器接口保持一致(二叉树你不能用length吧)


#### capacity


➰ **容量**:能存多少个**有效字符**(注意\0无效字符不算),要记得string类的底层是顺序表结构,`初始值是15`


![在这里插入图片描述](https://img-blog.csdnimg.cn/78a62fdd37554638a0e74f3c1b3c74fb.png)


#### ⚡resize vs reverse


➰**reserve** 和 **resize** 都是改变容量,申请**至少**n个字符的空间(字符串涉及对齐问题,后续详谈) ,但有所不同 ——


🤞1. `resize` - 开空间,并可以对空间**初始化**


![在这里插入图片描述](https://img-blog.csdnimg.cn/76c684157a27487497b4e2aac5212a6c.png)  
 翻译知道


* 如果是将元素个数**减少**,会把多出`size`的字符抹去,这不挺resize的吗(狗头)
* 如果是将元素个数增多,`void resize (size_t n);`,用`\0`**来填充**多出的元素空间,`void resize (size_t n, char c);`用`字符c`**来填充**多出的元素空间
* 注:resize在改变元素个数时,如果是将**元素个数增多**,可能会**改变容量的大小**;如果是将元素个数size减少,容量不变



void test_string14()
{
string s1(“JDG 总冠军”);
s1.resize(5);//size缩小成5,capacity不变

string s2("JDG 总冠军");
s2.resize(100);//填充'\0',size——>100,capacity->111(自动扩容)

string s3("JDG 总冠军");
s3.resize(100,'~');//填充'\0',size——>100,capacity->111(自动扩容)

}


➰ 2. **reserve** - 开空间。**在已知需要多少空间时,调用reserve**,可以避免频繁增容的消耗


![在这里插入图片描述](https://img-blog.csdnimg.cn/dd8993fc17dc4915a34c9ad4eb58ae01.png)


* 为字符串**预留空间**,**改变容量**。当然了不会改变有效元素个数size
* 给reserve的参数n小于string的容量时,是无效请求,并不会改变容量大小



#include

using namespace std;

int main()
{
string s1;
s1.reserve(100); // size - 0,capcacity->111

string s2("more than words");
s2.reserve(5);   // capacity和size仍为15

return 0;

}


#### ⚡clear


➰ **清空有效字符**,容量不变  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/8ac3da589fe849e4b1ce3b39b9043289.png)


#### ⚡empty


➰ **检测**字符串**是否为空串**


![在这里插入图片描述](https://img-blog.csdnimg.cn/bd0e2aafd9b84ab79fb6be8722240f59.png)


### 六、iterator 迭代器


第二种遍历的方法:迭代器,对于string类,无论正着还是倒着走,`[下标]`的方法都足够好用,为什么还要有迭代器?  
 🤞🤞事实上,迭代器是一种**通用的遍历方式**,且**用法类似**,**所有容器**都可以使用迭代器这种方式去访问修改,而list、map/set不支持[下标]遍历。结论是,对于string类,我们得会用迭代器,但是我们更喜欢用[下标]


#### 🌈正向迭代器


正向迭代器提供了两个函数——  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/32e9e6448f4c425da6c86b7704399fc8.png)


![在这里插入图片描述](https://img-blog.csdnimg.cn/eb73a31eaf824058a81c78f2e88d80c4.png)


🌈迭代器 iterator是**像**指针一样的类型,**不确定是不是**(薛定谔的猫),但它的用法像指针一样, 其区间`[ }`左闭右开



#include
#include

using namespace std;

int main()
{
string s(“more than words”);
// 1.可读
string::iterator it = s.begin();
while (it != s.end())
{
cout << *it << " ";
it++;
}
cout << endl;

// 2.可写
it = s.begin();
while (it != s.end())
{
	\*it += 1;
	it++;
}
cout << s <<endl;
return 0;

}


![在这里插入图片描述](https://img-blog.csdnimg.cn/a15a6bf941834424b6f8e2fcc5d39f99.png)


* iterator依然提供了两个版本,第二个是const变量
* 关于遍历的时候`!=`能不能改成`<=` ,可以但是没必要,因为在string的物理空间是连续的,其他容器list等不一定连续。


#### 🌈反向迭代器


也提供了两个成员函数


![在这里插入图片描述](https://img-blog.csdnimg.cn/b5a47ae4f19348ed952711a560bd7901.png)


![在这里插入图片描述](https://img-blog.csdnimg.cn/e63d2db2c553403c8638ab5f5aae4cc6.png)



void test_string5()
{
string s(“hello”);
string::reverse_iterator rit = s.rbegin();
//auto rit = s.rbegin();//auto 可以自动推导类型
while (rit != s.rend())
{
cout << *rit << " ";
rit++;
}
cout << endl;
}


![在这里插入图片描述](https://img-blog.csdnimg.cn/c7e5359c6637426fbc92a78cf7c8ce3c.png)


#### 🌈const迭代器


所谓的const迭代器就是针对const的版本嘛


* 普通迭代器可读可写,相当于string类模板中,类型为`T*`
* 而const迭代器不可写。这是因为是**const成员函数**,const修饰this指针指向的内容(相当于string类模板中,类型为`const T*`)


const迭代器也分**正向迭代器**和**反向迭代器**,且就是给`const对象用`的。这是因为const对象才能调用这里的const成员函数,返回const迭代器,不可写。


![在这里插入图片描述](https://img-blog.csdnimg.cn/06dad27080f1453482cdf3cebcae1cc1.png)  
 使用情况如下:



void test_string6()
{
string s(“hello”);
// const正向迭代器 - 可读不可写
string::const_iterator it = s.begin();
while (it != s.end())
{
cout << *it << " ";
it++;
}
cout << endl;

// const反向迭代器 - 可读不可写
string::const_reverse_iterator rit = s.rbegin();
while (rit != s.rend())
{
	cout << \*rit << " ";
	rit++;
}
cout << endl;

}


传参进func中,s是const对象,**自动调用第二个接口**,返回的是const\_iterator,要用const迭代器类型接收,且不能修改


![在这里插入图片描述](https://img-blog.csdnimg.cn/6a41c41c11a14af9a4a4dadb3aeab375.png)


`C++11`为了区分const迭代器和普通迭代器还提供了以下接口,不然调用时容易混淆


![在这里插入图片描述](https://img-blog.csdnimg.cn/aa5d8bdcb41c47df9a91f7c8e110585b.png)


#### 🌈范围for遍历


范围for是C++11提供的**语法糖🍬**,实际上底层编译器会替换成迭代器(反汇编里可以看出) **只能正向遍历**


🍬依次取`s`中的每个字符,赋值给`ch`


* **自动**迭代
* **自动判断结束**



#include
#include

using namespace std;

int main()
{
string s(“more than words”);
for (auto& ch : s)
{
cout << ch << " ";
}
cout << endl;

for (auto& ch : s)
{
	ch += 1;
}
cout << s << endl;
return 0;

}


ps:


* 若要修改,auto要加上&。因为`*it`会依次赋值给`ch`,**ch是\*it的拷贝**,\*it改变不影响ch,所以要加上&


### 七、Modifiers 修改


#### 🎨追加


![在这里插入图片描述](https://img-blog.csdnimg.cn/6f0ffde4112e4371adf269de26d34ad2.png)


`+=`**最好用也最常用**,因为既可以追加字符、也可追加字符串 ,其实底层调用了`append`和`push_back`



void test_string7()
{
string s(“hello”);
s.push_back(‘-’);
s.push_back(‘-’);
s.append(“world”);
cout << s << endl;

string str("我来了");
s += '@';//字符
s += str;//字符串
s += "JDG总冠军";
cout << s << endl;

}


![在这里插入图片描述](https://img-blog.csdnimg.cn/798ee9445943427fb7a4dc90911a884f.png)  
 其中append的迭代器可以选择性的打印字符串内容(了解即可)



string s(“hello”);
string str(“我来了”);

s.append(++str.begin(), --str.end());
string copy(s.begin() + 5, s.end() -5);


![在这里插入图片描述](https://img-blog.csdnimg.cn/20743bf8af1044c893e3425c24925852.png)


下面来研究尾插扩容容量变化 ——



void test_string8()
{
string s;
size_t sz = s.capacity();
cout << “making s grow:\n”;
for (int i = 0; i < 100; ++i)
{
s.push_back(‘c’);
if (sz != s.capacity())
{
sz = s.capacity();
cout << "capacity changed: " << sz << ‘\n’;
}
}
}


我们可以看见在vs下增容,第一次是两倍,后面是1.5倍的增容


![在这里插入图片描述](https://img-blog.csdnimg.cn/48a6ba91d67d4f43a33ed5630d69cb41.png)


如果提前知道是多少空间,可以调用`reserve`预留空间,避免频繁增容的消耗



s.resize(1000 , ‘x’); //开空间+初始化


![在这里插入图片描述](https://img-blog.csdnimg.cn/792c283dd94044e999bed8dafa5ef244.png)


#### 🎨插入和删除


🐋尽量少使用头部的插入和删除,因为要挪动,O(N)效率低


![在这里插入图片描述](https://img-blog.csdnimg.cn/54c8fb13d23143f0b0eb01f9c51d0c85.png)


🤞1️⃣小练习:在字符串中空格的地方插入一个%


我的第一想法:**遍历字符串**,遇到`' '`的时候,直接插入



void test_string9()
{
//在空格的地方插入一个%
string str(“JDG NB 总冠军”);
for (size_t i = 0; i < str.size(); ++i)
{
if (str[i] == ’ ')
{
str.insert(i, “20%”);
}
}
cout << str << endl;
}


但这样有没有问题呢?  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/8aad0c1361584b7f90ed6add31691a02.png)


那怎么样处理比较好呢?只需要在插入的地方`i`额外的`+3`,



void test_string9()
{
//在空格的地方插入一个%
string str(“JDG NB 总冠军”);
for (size_t i = 0; i < str.size(); ++i)
{
if (str[i] == ’ ')
{
str.insert(i, “20%”);
i += 3;
}
}
cout << str << endl;
}


2️⃣练习升级:**把字符串中遇到的空格替换成20%**


这就要引入`erase`:**删除**字符串中的字符  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/8b9cc405970d4762b239fc05a90ad786.png)



void test_string9()
{
//在空格的地方插入一个%
string str(“JDG NB 总冠军”);
for (size_t i = 0; i < str.size(); ++i)
{
if (str[i] == ’ ')
{
str.insert(i, “20%”);
i += 3;
}
}
//再把空格删除掉哦
for (size_t i = 0; i < str.size(); ++i)
{
if (str[i] == ’ ')
{
str.erase(i, 1);
}
}
cout << str << endl;
}


ps:最好不要自行挪动数据,因为`[]`会检查下标位置必须要小于`size`的,如果真的要挪动,要`resize`一下,增加长度


也有一种**空间换时间**的方法:创建新的串遍历,效率`O(N)`



void test_string9()
{
string str(“JDG NB 总冠军”);
string newstr;
for (size_t i = 0; i < str.size(); ++i)
{
if (str[i] != ’ ')
{
newstr += str[i];
}
else
{
newstr += “20%”;
}
}
cout << newstr << endl;
}


### 八、String operations 字符串操作


![在这里插入图片描述](https://img-blog.csdnimg.cn/a51948375d594ce3b95d45b70f49bf03.png)  
 打印字符串,都能打印,但意义不同 ——


![在这里插入图片描述](https://img-blog.csdnimg.cn/a4e3ad1c5556430297eba7beb3369423.png)


🤞前者是string类的**流插入运算符的重载**,以**对象**`size`为准,size是多少打印多少  
 后者是以**常量字符串对象\0**为准,遇到`\0`就结束(符合c语言标准)



> 
> 所以说`\0`**不一定是结束标志**,在string里会被忽视
> 
> 
> 


主要作用还是与函数接口接合——



string file("test.txt");	
FILE\* fout = fopen(s.c\_str(), "w");//打印文件

![在这里插入图片描述](https://img-blog.csdnimg.cn/631a160b51da4d7e9729bbeb05c5295d.png


#### 🌍substr 子串


➰· 取当前串的一个**子串**  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/a69c6946da9c4cb0bf2b37647ba6b2b7.png)


`len`:如果len比能取到的串长或使用缺省值npos,都是**能取多少取多少**


#### 🌍查找 find & rfind


🌊 1. 从字符串`pos位置`**从前向后**找字符c/字符串,返回该字符在字符串中的位置,找不到就返回`npos`


![在这里插入图片描述](https://img-blog.csdnimg.cn/59c73527859944f19c6b510445744589.png)


🌊 2. 从字符串pos位置**倒着找**找字符c/字符串,返回该字符在字符串中的位置


![在这里插入图片描述](https://img-blog.csdnimg.cn/40557d8990b44419bf682d76474d77a0.png)  
 💢小练习:**取字符串的后缀**



void test_string11()
{
string str(“test.cpp”);
//找出后缀
size_t pos = str.rfind(‘.’);//面对多后缀的最好用 rfind
if (pos != string::npos)
{
//string buff = str.substr(pos, str.size() - pos);
string buff = str.substr(pos);//因为是取到结束
cout << buff << endl;
}
}


![在这里插入图片描述](https://img-blog.csdnimg.cn/008a0c9a455b4ed3bc278385a2ec56da.png)


但是这样写有没有说明问题呢?如果后缀是`test.cpp.tar.zip`呢?要取最后一个后缀


这样就要将`find` ——》 `rfind`,即可解决


💢**解析出网址的这三个部分**:协议 - 域名 - 资源



#include
#include

using namespace std;

int main()
{
string url = “https://cplusplus.com/reference/string/string/substr/”;
size_t pos1 = url.find(“😕/”);
if (pos1 == string::npos)
{
cout << “非法字符串” << endl;
return;
}
//取协议
string protocol = url.substr(0, pos1);
cout << protocol << endl;

size_t pos2 = url.find('/', pos1 + 3);
if (pos1 == string::npos)
{
	cout << "非法字符串" << endl;
	return;
}
string domain = url.substr(pos1 + 3, pos2 - pos1 - 3);//取域名
cout << domain << endl;

string uri = url.substr(pos2 + 1);//取资源
cout << uri << endl;

}


![在这里插入图片描述](https://img-blog.csdnimg.cn/024e5e59cceb4a969bb01f586d9fd636.png)


#### 💢find 和find\_first\_of 区别


![在这里插入图片描述](https://img-blog.csdnimg.cn/44f7876a304d41e9af1a5d7657a7447b.png)  
 find\_first\_of:只要出现要寻找的**串里的任意字符**都找出来


吐槽一下:`find_first_of` 更应该叫find\_any\_of,但我们要尊重语法


![在这里插入图片描述](https://img-blog.csdnimg.cn/fce3b4f21e404e6f984781956d197914.png)


### 九、非成员函数重载


#### 💦流插入&流提取


注意注意:流插入和流提取都是以`空格、回车`作为**结束标志**的。这意味着如果想要输入一个字符串,最终可能只读入了一个单词,剩余的留在缓冲区里。


![在这里插入图片描述](https://img-blog.csdnimg.cn/d381dfb80b61443dad294f8d89e86003.png)


于是我们引入了`getline`,做题会遇到




![img](https://img-blog.csdnimg.cn/img_convert/8fe0fe47b2459552061457bfb86a9a88.png)
![img](https://img-blog.csdnimg.cn/img_convert/acb1a274e2f7e599cae2f527ac5acec8.png)

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!**

**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**

**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618668825)**

现要寻找的**串里的任意字符**都找出来


吐槽一下:`find_first_of` 更应该叫find\_any\_of,但我们要尊重语法


![在这里插入图片描述](https://img-blog.csdnimg.cn/fce3b4f21e404e6f984781956d197914.png)


### 九、非成员函数重载


#### 💦流插入&流提取


注意注意:流插入和流提取都是以`空格、回车`作为**结束标志**的。这意味着如果想要输入一个字符串,最终可能只读入了一个单词,剩余的留在缓冲区里。


![在这里插入图片描述](https://img-blog.csdnimg.cn/d381dfb80b61443dad294f8d89e86003.png)


于是我们引入了`getline`,做题会遇到




[外链图片转存中...(img-Scf0uCVJ-1715755722074)]
[外链图片转存中...(img-QYvU6zDl-1715755722074)]

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!**

**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**

**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618668825)**

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值