Lesson 08 string类 (中)

C++:渴望力量吗,少年?

文章目录

  • 二、string类的介绍与使用
    • 2. 使用
        • (5)string类对象的修改操作
  • 三、拷贝
    • 1. 引入
    • 2. 浅拷贝
    • 3. 深拷贝
  • 总结


二、string类的介绍与使用

2. 使用

(5)string类对象的修改操作
函数名称功能说明
push_back在字符串后尾插字符
append在字符串后追加一个字符串
operator+= (重点)在字符串后追加字符串str
c_str(重点)返回C格式字符串
find + npos(重点)从字符串pos位置开始往后找字符c,返回该字符在字符串中的位置
rfind从字符串pos位置开始往前找字符c,返回该字符在字符串中的位置
substr在str中从pos位置开始,截取n个字符,然后将其返回

注意:
  a. 在string尾部追加字符时,s.push_back(c ) / s.append(1, c) / s += ‘c’ 三种的实现方式差不多,一般情况下string类的+=操作用得比较多,+=操作不仅可以连接单个字符,还可以连接字符串
  b. 对string操作时,如果能够大概预估到放多少字符,可以先通过reserve把空间预留好。

void test_string6()
{
    cout << "我是test_string6 :" << endl;
    string s;
    //s.reserve(100);//保留至少100个字节的空间,如果提前知道所需的空间,可以提前开好,因为扩容需要代价
    //容器的容量不一定就是我们开的那个,可能大于这个数字

    size_t old = s.capacity();//Return size of allocated storage(返回已分配的空间大小)
    cout << "初始" << s.capacity() << endl;

    for (size_t i = 0; i < 100; i++)//观察扩容的情况
    {
        s.push_back('x');

        if (s.capacity() != old)
        {
            cout << "此时i = " << i << ", 扩容:" << s.capacity() << endl;
            old = s.capacity();
        }
    }

    s.reserve(10);//string可以自由地优化,并使字符串的容量大于 n。
    cout << s.capacity() << endl;
}

void test_string7()//考虑现有的size和capacity的关系
{
    cout << "我是test_string7 :" << endl;
    string s1("hello world");
    cout << s1 << endl;
    cout << s1.size() << endl;//s.size() == s.length(),这两个都不包括斜杠零
    cout << s1.capacity() << endl;

    //s1.resize(13);//多出来的空间放置斜杠零
    //s1.resize(13, 'x');//已有数据个数小于resize的个数,相当于插入新的数据
    s1.resize(20, 'x');//如果resize开的空间大于最开始的capacity也就是15,就会自动扩容
    cout << s1 << endl;
    cout << s1.size() << endl;
    cout << s1.capacity() << endl;

    s1.resize(5);//已有数据的空间大于resize的空间,相当于删除数据
    cout << s1 << endl;
    cout << s1.size() << endl;
    cout << s1.capacity() << endl;

    string s2;
    s2.resize(10, '#');//字符串没有数据/没有初始化,相当于直接填充数据
    cout << s2 << endl;
    cout << s2.size() << endl;
    cout << s2.capacity() << endl;

    s2[0]++;
    s2.at(0)++;//Return value:The character at the specified position in the string.(返回特定位置的字符)
    cout << s2 << endl;
}

void test_string8()
{
    cout << "我是test_string8 :" << endl;
    string ss("world");

    string s;
    s.push_back('#');
    s.append("hello");//在对象s的结尾追加,和pushback、+=的效果差不多,一般使用+=多一些
    s.append(ss);
    cout << s << endl;

    s += '#';
    s += "hello";
    s += ss;
    cout << s << endl;

    string ret1 = ss + '#';//尽量使用 +=,因为 + 的拷贝构造次数会更多,影响效率
    string ret2 = ss + "hello";
    cout << ret1 << endl;
    cout << ret2 << endl;
}

void test_string9()
{
    cout << "我是test_string9 :" << endl;
    std::string str("xxxxxxx");
    std::string base = "The quick brown fox jumps over a lazy dog.";

    //str = base;//可以直接用 = 赋值
    //cout << str << endl;

    str.assign(base);//相当于base赋值给str,会覆盖原来的值
    std::cout << str << '\n';

    str.assign(base, 5, 10);//从base下标为5的位置开始将10个字符赋值给str
    std::cout << str << '\n';

    //str.assign(base.begin()+16,base.end()-12);//参数也可以是迭代器
}

void test_string10()
{
    cout << "我是test_string10 :" << endl;
    // insert/erase/repalce能不用就尽量不用,因为他们都涉及挪动数据,效率不高
    // 接口设计复杂繁多,需要时查一下文档即可
    std::string str("hello world");
    str.insert(0, 1, 'x');//在下标为第一个参数的位置插入个数为第二个参数的第三个参数
    str.insert(str.begin(), 'x');
    cout << str << endl;

    str.erase(5);//从下标为5的位置开始擦除内容,第二个参数是缺省参数,不写默认擦除第一个参数后面的所有内容
    cout << str << endl;

    std::string s1("hello world");
    s1.replace(5, 3, "%%20");//将从指定位置开始的指定个数字符替换为指定字符(串)
    //3:Number of characters to replace (if the string is shorter, as many characters as possible are replaced).
    cout << s1 << endl;

    // 要求将空格替换为20%(以空间换时间)(replace效率不够高)
    std::string s2("The quick brown fox jumps over a lazy dog.");
    string s3;
    for (auto ch : s2)
    {
        if (ch != ' ')
        {
            s3 += ch;
        }
        else
        {
            s3 += "20%";
        }
    }

    //s2 = s3;
    //s2.assign(s3);
    printf("s2:%p\n", s2.c_str());//c_str可以返回这个对象的指针
    printf("s3:%p\n", s3.c_str());

    //交换的目的是让s2的内容变成修改之后的内容
    swap(s2, s3);//注意有swap模板库,也有全局函数swap,还有string自己提供的swap,如果用的话一般自定义类型不要用模板的swap,因为要拷贝构造的次数比较多
    //不过一般直接调用swap交换字符串也不会调用模板库的,因为匹配的模板和匹配的已经实现的函数之间编译器会优先使用已经实现的函数
    //s2.swap(s3);

    printf("s2:%p\n", s2.c_str());
    printf("s3:%p\n", s3.c_str());

    cout << s2 << endl;
}

void test_string11()
{
    cout << "我是test_string11 :" << endl;
    string s1("test.cpp.tar.zip");
    //返回找到的下标
    //size_t i = s1.find('.');//正向查找第一个 . 
    size_t i = s1.rfind('.');//反向查找第一个 .
    cout << i << endl;

    string s2 = s1.substr(i, 3);//从下标为i的位置开始取子串,第二个参数没写就取剩下的全部
    cout << s2 << endl;

    //string s3("https://legacy.cplusplus.com/reference/string/string/rfind/");
    string s3("ftp://www.baidu.com/?tn=65081411_1_oem_dg");
    // 协议
    // 域名
    // 资源名

    string sub1, sub2, sub3;
    size_t i1 = s3.find(':');
    if (i1 != string::npos)//因为找不到对应的字符是返回npos
        sub1 = s3.substr(0, i1);//注意是左闭右开的区间,substr返回一个子串
    else
        cout << "没有找到i1" << endl;

    size_t i2 = s3.find('/', i1 + 3);
    if (i2 != string::npos)
        sub2 = s3.substr(i1 + 3, i2 - (i1 + 3));
    else
        cout << "没有找到i2" << endl;

    sub3 = s3.substr(i2 + 1);//取到末尾

    cout << sub1 << endl;
    cout << sub2 << endl;
    cout << sub3 << endl;
}

void test_string12()
{
    cout << "我是test_string12 :" << endl;
    /*std::string str("Please, replace the vowels in this sentence by asterisks.");
    std::size_t found = str.find_first_not_of("abc");//找到字符串第一个不是abc的字符并返回下标
    while (found != std::string::npos)
    {
        str[found] = '*';
        found = str.find_first_not_of("abcdefg", found + 1);//第二个参数:Position of the first character in the string to be considered in the search.
    }

    std::cout << str << '\n';*/

    std::string str("Please, replace the vowels in this sentence by asterisks.");
    std::size_t found = str.find_first_of("abcd");//找到第一个是abcd中其中一个字符的并返回下标
    while (found != std::string::npos)
    {
        str[found] = '*';
        found = str.find_first_of("abcd", found + 1);
    }

    std::cout << str << '\n';

}

int main()
{
    test_string6();
    test_string7();
    test_string8();
    test_string9();
    test_string10();
    test_string11();
    test_string12();

    return 0;
}

  string类中还有一些其他的操作,这里不一一列举,大家在需要用到时查文档即可。

三、拷贝

1. 引入

  上面已经对string类进行了简单的介绍,其他不太常用的函数就不再写了,只要能够保证上面的内容都能熟练运用即可。为什么模拟实现string类?模拟string类最主要是实现string类的构造、拷贝构造、赋值运算符重载以及析构函数,只有能够模拟出来,才是真正了解它的底层逻辑。
  问题:以下string类的实现是否有错?
代码如下:

class String {
public:
	String(const char* str = "")
	{
		if (nullptr == str)
		{
			assert(false);
			return;
		}

		_str = new char[strlen(str) + 1];
		strcpy(_str, str);
	}

	~String()
	{
		if (_str)
		{
			delete[] _str;
			_str = nullptr;
		}
	}
private:
	char* _str;
};

// 测试
void TestString()
{
	String s1("hello bit!!!");
	String s2(s1);
}

  这段代码其实是有很大的问题的,这个关于拷贝的问题也是我们学习C++经常会遇到的问题,所以还是得理解为什么。
在这里插入图片描述
  上述String类没有显式定义其拷贝构造函数与赋值运算符重载,此时编译器会合成默认的,当用s1构造s2时,编译器会调用默认的拷贝构造。最终导致的问题是,s1、s2共用同一块内存空间,在释放时同一块空间被释放多次而引起程序崩溃,这种拷贝方式,称为浅拷贝。

2. 浅拷贝

  浅拷贝:也称位拷贝,编译器只是将对象中的值拷贝过来。如果对象中存在管理的资源,最后就会导致多个对象共享同一份资源,当一个对象销毁时就会将该资源释放掉,而此时另一些对象不知道该资源已经被释放,以为还有效,所以当继续对资源进项操作时,就会发生发生了访问违规。

3. 深拷贝

  如果一个类中涉及到资源的管理,其拷贝构造函数、赋值运算符重载以及析构函数必须要显式给出。一般情况都是按照深拷贝方式提供。
  上面的代码可以采用深拷贝解决浅拷贝问题,即:每个对象都有一份独立的资源,不和其他对象共享。
在这里插入图片描述
  如图,显式地定义拷贝构造函数,在初始化列表重新为_pStr开辟一个新的空间,再把数据从就空间拷贝过去,这样就实现了深拷贝。


总结

  前面这两小节主要还是为了下一节地模拟实现做准备,要尽可能做到理解并熟练运用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/203561.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

网络通信概述

文章目录 IP地址端口号协议三要素作用 五元组协议分层OSI七层模型TCP/IP 五层模型应用层传输层网络层数据链路层物理层 封装和分用发送方 - 封装中间转发接收方 - 分用 一般认为计算机网络就是利用通信线路和通信设备将地理上分散的、具有独立功能的多个计算机系统按不同的形式…

QT学习_16_制作软件安装包

1、准备软件exe及其运行环境 参考&#xff1a;Qt学习_12_一键生成安装包_江湖上都叫我秋博的博客-CSDN博客 这篇博客记录了&#xff0c;如何用window的脚本&#xff0c;一键生成一个可以免安装的软件压缩包&#xff0c;解压缩后&#xff0c;点击exe文件就可以直接运行。 这一…

基于SSM实现的图书管理系统

一、系统架构 前端&#xff1a;jsp | js | css | jquery | layui 后端&#xff1a;spring | springmvc | mybatis 环境&#xff1a;jdk1.7 | mysql | maven | tomcat 二、代码及数据库 三、功能介绍 01. 登录页 02. 首页 03. 借阅管理 04. 图书管理 05. 读者管理 06. 类型管理…

宽量程双计数器测量方法

如要测量计数器信号的数字频率或周期&#xff0c;可使用双计数器方法测量宽量程信号。该方法适于待测量信号的范围较广且整个范围都需要较高测量精度的情况。关于使用宽量程测量方法提高测量精度的详细信息&#xff0c;见量化误差章节。也可使用该方法测量比计数器时基频率更高…

阿里云RDS标准版(x86) vs 经济版(ARM)性能对比

概述 阿里云数据库在去年云栖大会上发布了基于阿里倚天芯片&#xff08;ARM架构&#xff09;的RDS实例&#xff0c;后正式命名为经济版。本文通过标准的sysbench测试&#xff0c;来看看相比与标准版&#xff0c;经济版是否更加“经济”&#xff0c;以帮助开发者选择适合自己的…

什么是API? (应用程序编程接口)

我们经常听到 API 这个专业名称。那么什么是 API 呢&#xff1f; 定义 API&#xff08;Application Programming Interface&#xff0c;应用程序接口&#xff09;是一些预先定义的函数&#xff0c;或指软件系统不同组成部分衔接的约定。目的是提供应用程序与开发人员基于某软…

信号收尾.

sigaction 信号捕捉 它也是信号捕捉&#xff0c;不仅能处理普通信号还能处理实时信号&#xff0c;但我们不管实时信号 我们发现函数名和形参中结构体名一样都是sigaction&#xff0c;这在c/c中允许吗&#xff1f; 不建议&#xff0c;但是可以 signo你要捕捉几号信号 输入型参…

《一带繁花一路歌》趣味化讲述“一带一路”故事,生动化展现“文明互鉴”美好图景

2023年&#xff0c;总台《艺览天下》推出“一带一路”10期特别节目《一带繁花一路歌》&#xff0c;节目邀请“一带一路”沿线国家驻华大使等重量级嘉宾&#xff0c;在地标推介、故事分享、现场互动等环节里趣味化讲述“一带一路”故事&#xff0c;生动地展现出“文明互鉴”的美…

互联网上门家政小程序服务小程序

过去&#xff0c;家政门店主要依靠传统地推方式&#xff0c;如贴广告、发传单、亲友推荐等&#xff0c;被动地等待客户上门。这种方式使得拓展客户的效率低下&#xff0c;而且家政服务市场还存在一些问题&#xff0c;如市场竞争混乱、供需不平衡、员工素质参差不齐等&#xff0…

【elementUI】el-tab相关问题

Tabs 标签页 分隔内容上有关联但属于不同类别的数据集合。 <template><el-tabs v-model"activeName" tab-click"handleClick"><el-tab-pane label"用户管理" name"first">用户管理</el-tab-pane><el-tab-p…

uniapp和vue3+ts实现自定义头部导航栏左侧胶囊内容

由于某些原因&#xff0c;可能需要我们自己定义头部导航栏的内容&#xff0c;实现各种设计师画的设计稿&#xff0c;所以就需要这个自定义的组件&#xff0c;实现的内容&#xff1a;自定义标题和左侧胶囊图标内容&#xff0c;也可以自定义搜索内容到里面&#xff0c;实现的效果…

软件测试jmeter基本使用

1安装与配置 1.jdk下载 下载地址&#xff1a;https://www.oracle.com/java/technologies/downloads/#jdk18-windows&#xff08;压缩包中会给&#xff09; 2.jmeter下载 Apache JMeter - Download Apache JMeter&#xff08;压缩包中有&#xff09; 3.操作教学 打开软件后新…

学生用台灯哪个品牌比较好?2023考研护眼台灯推荐

随着科技时代的到来&#xff0c;人们的生活水平不断提高&#xff0c;也面临着许多问题&#xff0c;近期随着央视报道的全国中小学学生的近视率&#xff0c;护眼台灯再次被众人推上热潮&#xff0c;护眼台灯能够提供柔和自然的光感非常舒适&#xff0c;而且使用起来非常便捷。不…

JavaScript值和引用

前端面试大全JavaScript值和引用 &#x1f31f;经典真题 &#x1f31f;值和引用相关内容 1. 简单值&#xff08;原始值&#xff09; 2. 复杂值&#xff08;引用值&#xff09; 3. 访问方式 4. 比较方式 5. 动态属性 6. 变量赋值 &#x1f31f;真题解答 &#x1f31f;…

v-for和v-if同时使用时的问题:

当在同一个标签上同时使用 v-for 和 v-if 时&#xff0c;可能会导致意外的结果或错误。这是因为Vue的编译规则中&#xff0c;v-for 比 v-if 优先级更高&#xff0c;意味着 v-for 会先执行&#xff0c;然后 v-if 根据条件进行渲染或移除子元素。 在某些情况下&#xff0c;使用 …

ardupilot开发 --- 机载计算机 篇

0. 前言 关于机载计算机&#xff1b; 1. APSync 说到机载计算机Companion computer就不得不提另一个关键词APSync&#xff1b;APSync简化了机载计算机的设置&#xff0c;以便它可以为ArduPilot提供额外的功能&#xff0c;并简化与互联网服务的集成&#xff1b;提供日志下载和…

Linux:docker镜像的创建(5)

1.基于已有镜像创建 步骤&#xff1a; 1.将原始镜像加入容器并运行 2.在原始镜像中部署各种服务 3.退出容器 4.使用下面命令将容器生成新的镜像 现在我们在这个容器里做了一些配置&#xff0c;我们要把他做成自己镜像 docker commit -m "centos7_123" -a "tarr…

基于matlab的图像去噪算法设计与实现

摘 要 随着我们生活水平的提高&#xff0c;科技产品飞速更新换代&#xff0c;在信息传输中&#xff0c;图像传输所占的比重越来越大。但自然噪声会在图像传输时干扰其传输过程&#xff0c;甚至会使图片不能表达其原来的意义。去噪处理就是为了去除图像中的噪声&#xff0c;从而…

[英语学习][4][Word Power Made Easy]的精读与翻译优化

[序言] 今日继续阅读两段原版翻译, 有一点点生硬, 还是耐不住寂寞, 去优化了. [英文学习的目标] 提升自身的英语水平, 对日后编程技能的提升有很大帮助. 希望大家这次能学到东西, 同时加入我的社区讨论与交流英语相关的内容. [原著英文与翻译版对照][第18页] "And suerl…

【端到端可微1】端到端的训练,使用反向传播,要求过程可微分

文章目录 背景想法&#xff1a; Weighted least-squares fitting方法&#xff1a; Backpropagating through the fitting procedure.温习之前的基础前向传播反向传播 总结 背景 想做一个端到端训练的模型&#xff0c;将最小二乘嵌入其中。因此有了这系列文章。 想法&#xff…