当前位置: 首页 > 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的成员函数比较多,所以需要下讲继续讲了,喜欢的可以一键三连哦!

http://www.xdnf.cn/news/234127.html

相关文章:

  • 手动实现二叉搜索树
  • AGI时代来临?2030年AI将如何改变人类社会?
  • Spark SQL 之 DAG
  • Linux容器大师:K8s集群部署入门指南
  • 校平机:金属板材加工的核心设备
  • 1295. 统计位数为偶数的数字
  • 大小写问题
  • 5.运输层
  • 解决在Mac上无法使用“ll”命令
  • python与c++变量赋值的区别
  • 【Linux庖丁解牛】—环境变量!
  • 深入解析词嵌入(Word2Vec、GloVe)技术原理:从词语到向量的转变
  • Transformer 模型及深度学习技术应用
  • Langchain+文本摘要-refine
  • Java零基础入门Day3:程序流程控制
  • Flowith:解放思维的AI画布让创意与效率如泉涌
  • 动画震动效果
  • 【Bootstrap V4系列】学习入门教程之 加载必要文件和入门模板
  • javascript 深拷贝和浅拷贝的区别及具体实现方案
  • 【每日八股】复习 Redis Day4:线程模型
  • NLP 分词技术学习
  • 【Dify系列教程重置精品版】第四章:实现Dify的 hello world
  • ISO 26262认证步骤
  • 【Java面试笔记:进阶】30.Java程序运行在Docker等容器环境有哪些新问题?
  • 楼宇智能化三、五章【期末复习】
  • 芯知识|小体积语音芯片方案WTV/WT2003H声音播放ic应用解析
  • 楼宇智能化四章【期末复习】
  • (eNSP)Smart Link配置实验
  • MicroPython for esp32s3开发HX711称重模块指南
  • rk3568 A/B系统 OAT升级 实践