当前位置: 首页 > news >正文

C++初阶-string类1

目录

1.为什么学习string类

1.1C语言中的字符串

1.2一个面试题

2.标准库中的string类

2.1string类(简介)

2.2auto关键字和范围for

2.2.1auto关键字

2.2.2范围for

2.3string类对象的常见构造

3.string的构造函数

4.string的遍历及修改

5.总结



1.为什么学习string类

1.1C语言中的字符串

C语言中,字符串是以'\0'结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列
的库函数,但是这些库函数与字符串是分离开的,不太符合OOP的思想,而且底层空间需要用户
自己管理,稍不留神可能还会越界访问。

1.2一个面试题

字符串相加:

https://leetcode.cn/problems/add-strings/description/、

在OJ中,有关字符串的题目基本以string类的形式出现,而且在常规工作中,为了简单、方便、
快捷,基本都使用string类,很少有人去使用C库中的字符串操作函数。

2.标准库中的string类

2.1string类(简介)

string类的官方文档:https://cplusplus.com/reference/string/string/?kw=string

之后我们将围绕这个文档进行一系列string类的讲解。

2.2auto关键字和范围for

2.2.1auto关键字

这不是我们现在学习的重点,不过之后要用到的。

(1)在早期C/C++中auto的含义是:使用auto修饰的变量,是具有自动存储器的局部变量,后来这个不重要了。C++11中,标准委员会变废为宝赋予了auto全新的含义即:auto不再是一个存储类型指示符,而是作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期
推导而得。
(2)用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须加&
(3)当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际只对第一个类型进行推导,然后用推导出来的类型定义其他变量。
(4)auto不能作为函数的参数,可以做返回值,但是建议谨慎使用
(5)auto不能直接用来声明数组

#include<iostream>
using namespace std;
class Date
{ };
int main()
{auto a = 10;//识别出a为整型auto c = 10.3;//识别出c为double类型auto d = 10.1f;//识别出d为float类型Date e;auto f = e;//识别出f为Date类型auto b;//必须初始化,因为要自动识别等号右边的类型auto g = 0, h = 1;//g和h都为整型auto i, j = 1;//能识别出j为整型,而不能识别iauto k = 1.0, l = 2;//推导出k为double类型,而l为int类型,所以会报错auto& m = a;//可以用引用,写return 0;
}

第五点在C++11是不支持的,但是在C++20后就支持了,所以现在作为函数参数时也是没问题的。

auto func3()
{//没有问题//可以通过返回值推导类型return 3;
}

但若用auto作为返回值来层层调用就会很恶心,因为如果每一个都用auto作为返回类型,那么我们就需要去一直找到返回值开始确定的地方,如果有报错就非常难受,所以建议还是自己写类型吧。

int main()
{auto x = 1;auto y = &x;auto* z = &x;auto& m = x;return 0;
}

我们可以推导出y、z都为指针类型,m是引用。但是z和y的定义是有区别的,如果像y定义的那种写法,等号右边可为任意类型,而若用z这种写法,那么等号右边就只能为指针类型了,且z也必须为指针。

如果我们auto arr[]={4,5,6};这种写法是错误的,不能推导数组的类型。

日常中我们并不是auto用来写这种简单的类型的,我们可以用在类型名很长的时候,如之后可能用到的类型名:std::map<std::string,std::string>dict={};这种写法就不需要全部写出来了,直接用auto即可。

2.2.2范围for

(1)对于一个有范围的集合而言,由程序员来说明循环的范围是多余的,有时候还会容易犯错误。因此C++11中引入了基于范围的for循环。for循环后的括号由冒号“ :”分为两部分:第一部分是范围内用于迭代的变量,第二部分则表示被迭代的范围,自动迭代,自动取数据,自动判断结束。
(2)范围for可以作用到数组和容器对象上进行遍历
(3)范围for的底层很简单,容器遍历实际就是替换为迭代器,这个从汇编层也可以看到。

#include<iostream>
using namespace std;
int main()
{int arr[10] = { 0 };//普通写法for (size_t i = 0; i < 10; i++){cout << i << " ";}cout << endl;//范围for写法for (size_t i : arr){cout << i << " ";}cout << endl;return 0;
}

结果为:

这样能证明i是能作为一个局部变量来做arr[i]的打印的

若这样写:

#include<iostream>
using namespace std;
int main()
{int arr[10] = { 0 , 1,2,3,4,5,6,7,8,9 };//普通写法for (size_t i = 0; i < 10; i++){cout << i << " ";}cout << endl;//范围for写法for (size_t i : arr){cout << arr[i] << " ";}cout << endl;return 0;
}

则结果为:

证明这个i是一直在变化的,而且不会因为没指定范围而越界的问题,且i是一直在++的。

我们不能这样写(一般),若不修改,则需要加const;若修改则需要加引用。(要改变数组的情况下)

为什么不会修改的?

其实刚刚我说错了,就是说i是arr[i]的拷贝,i的改变不会影响arr中的值;故要这样写:

#include<iostream>
using namespace std;
int main()
{int arr[10] = { 0,1,2,3,4,5,6,7,8,9 };for (auto& e : arr){e *= 2;}for (const auto e : arr){cout << e << " ";}cout << endl;return 0;
}

这样写的打印结果是:

我们一般要加引用,防止我们在循环中修改时就不会影响arr了。

若我们把auto 改为具体类型也不会报错的,只是我想让你们记得用而已,不过建议用auto,因为之后定义的东西多了,就会很难找那个数组的定义时的开始类型了。

2.3string类对象的常见构造

这是三个默认构造函数和一个拷贝构造函数,一般我们需要注意的就是前面两个构造函数。

而我们需要的就是知道和了解这些构造函数,我们需要了解重要的string类里面的成员函数。当然我们需要根据下面的表格的函数来进行讲解:

当然这个文档不是比较好用,我们需要进入官方文档:https://legacy.cplusplus.com/reference/

搜索string 就可以看到搜索结果:

下面的内容与上张照片相同,我们需要点进

切换为:C++11版本才能看的更多重载函数(但现在我们还没学得深入,我们基本上看的是C++98版本的)。

虽然我们看到的是英文文档,我们需要看文档时用连蒙带猜的方式来得出一个函数的作用,虽然我们可以翻译,但是你看一下翻译后的界面就是很烦的:

虽然有些翻译的还行,但是这个确实看起来不是很舒服,建议还是看英文的。

进入主题吧!

3.string的构造函数

我们讲解构造函数前先说一下:不是每一个成员函数都会讲解,我们只讲重要的,有些我们只要知道它有就可以了,因为string设计的时候有些部分有重叠的地方,之后会体现的,所以有很多冗余的部分,也有一些用得不多的地方,这个是需要注意的。而且我现在是讲用法,讲完string的所有成员函数后,会自己实现那些比较重要的成员函数(只要在string类中用到的我们就简单称为成员函数,有些是相当于友元的,但是我们还是要学的)。

最常用的构造函数是1、2、3、4(2是拷贝构造)

这些构造函数重载得比较多,我们暂时只看这三个,第二个是拷贝构造,我们来猜一下第三个函数的功能,它看似是拷贝构造的重载,但因为它有额外的参数且没有给全缺省。我们需要看:

我们从(3)看出,这个函数的作用是:拷贝从pos位置开始取len个字符拷贝,len的缺省值为npos(先不管,是一个整型的最大值)。简单来说是从pos位置取len个字符拷贝到str里面。注意:虽然我们没有说是从哪个地方拷贝来的,因为成员函数第一个形参默认为this指针,而这个指针是不会显式给的,而在调用时我们是直接用this->_str(string类里面的数组)。

我们是来用的,底层如何实现我们需要到后面几篇博客里面的:string成员函数的手动实现里面再讲。

在现阶段,我只需要演示用法,先了解一下,之后会讲底层的,所以现在的内容要讲解很多。

记得包含头文件string来用这个类里面的函数。

#include<iostream>
using namespace std;
#include<string>
int main()
{//(1)string s1;//(4)//常量字符串初始化string s2("Hello world");//(2)string s3(s2);//(3)string s4(s2, 6, 10);//(3)string s5(s2,6);cout << s1 << endl;cout << s2 << endl;cout << s3 << endl;cout << s4 << endl;cout << s5 << endl;return 0;
}

打印结果为:

所以这就是我们的用法。

第五个函数的意思是取s的前n个字符到_str里面(初始化)。

第六个用n个c字符取初始化。

这都是根据那个文档来推出来的。

析构函数就是简单的把那些东西全部置为空等等作用,这个就不讲了。

赋值运算符重载函数:

有三个重载函数:

分别意思是:用str(string类型)去赋值给等号左边的string对象;用字符串去给string对象赋值;用一个字符取赋值。一般情况下是用第一个,。第一个也是标准的,不写也会自动生成的。

如:

#include<iostream>
using namespace std;
#include<string>
int main()
{string a("abcdefg");//(1)string b;b = a;//(2)string c ;c = "abcdefghijk";//(3)string d ;d = 'a';cout << a << endl;cout << b << endl;cout << c << endl;cout << d << endl;return 0;
}

运行结果如下:

4.string的遍历及修改

一般我们使用的是下标+[]的形式进行遍历的,这种方式我们不仅可以遍历还可以修改,如下使用方式:

#include<iostream>
using namespace std;
#include<string>
int main()
{string s2("hello world");//遍历方式1//下标加[]for (size_t i = 0; i < s2.size(); i++){s2[i] += 1;}for (size_t i = 0; i < s2.size(); i++){cout << s2[i] << endl;}return 0;
}

其中size()获取string的字符个数。当然我们在string中可以直接打印s2(<<运算符重载)cout<<s2;

而这种方式在string中用了[]运算符重载的知识,所以一般我们可以视为如下形式来实现[]的运算符重载:

#include<iostream>
using namespace std;
#include<string>
#include<assert.h>
namespace td
{class string{//[]运算符重载char& operator[](size_t pos){assert(pos < _size);return _str[pos];}private:char* _str;size_t _size;size_t _capacity;};
}

在不考虑模板的情况下底层大概是这样的形式来写这个[]的运算符重载。因为返回的是引用,所以导致了[]可以修改(修改会影响string对象)。

本质上是把s2+=[i]转换为s2.operator[](i) += 1;这样是让代码可读性更高了。

但是在真正string类里面定义了两个[]的运算符重载:

若调用第一个[]的重载,则可读可写;而第二个[]的重载,则是对于const的string对象用的。
否则就涉及到权限放大了,这样不会让const string对象修改了。

如:

#include<iostream>
using namespace std;
#include<string>
#include<assert.h>
int main()
{//普通成员对象调用第一个[]的string s2("hello world");for (size_t i = 0; i < s2.size(); i++){s2[i] += 1;}for (size_t i = 0; i < s2.size(); i++){cout << s2[i] << " ";}cout << endl;//const成员对象调用第二个[]的const string s5("xxxxxxxx");s5[0] = 'y';return 0;
}

那么结果就为:

因为const的string对象我们只可以读不可以写。

5.总结

这篇博客讲了string的一些基本知识和一些成员函数的用法,但是由于string的成员函数比较多,所以需要下讲继续讲了,喜欢的可以一键三连哦!

相关文章:

  • Hadoop虚拟机中配置hosts
  • 微信小程序 XSS 防护知识整理
  • 上海车展,世界模型 + VLA,城区智驾进入下半场
  • 同时启动俩个tomcat压缩版
  • spring--事务详解
  • react-10样式模块化(./index.module.css, <div className={welcome.title}>Welcome</div>)
  • 神经网络用于地震数据时空均匀插值的方法与开源资料
  • 六、UI自动化测试06--PO设计模式
  • micro-app前端微服务原理解析
  • 论文笔记(八十二)Transformers without Normalization
  • linux系统加固
  • 逻辑回归之参数选择:从理论到实践
  • GNU gettext 快速上手
  • 两向量平行公式、向量与平面平行公式、两平面平行公式;两向量垂直公式、向量与平面垂直公式、两平面垂直公式
  • 基于 HT 构建 2D 智慧仓储可视化系统的技术解析
  • IP 地址和 MAC 地址是如何转换的
  • mac下载homebrew 安装和使用git
  • 3.2goweb框架GORM
  • 基于BM1684X+RK3588的智能工业视觉边缘计算盒子解决方案
  • c++线程的创建
  • “译通天下·言立寰宇”:华东师大翻译家的精神传承
  • 中国代表:美“对等关税”和歧视性补贴政策严重破坏世贸规则
  • 史学巨擘的思想地图与学术路径——王汎森解析梁启超、陈寅恪、傅斯年
  • “光荣之城”2025上海红色文化季启动,红色主题市集亮相
  • 运动健康|不同能力跑者,跑步前后营养补给差别这么大?
  • 【社论】人工智能,年轻的事业