【C++初阶】string类

news2024/11/15 20:07:17

【C++初阶】string类

🥕个人主页:开敲🍉

🔥所属专栏:C++🥭

🌼文章目录🌼

1. 为什么学习string类?

    1.1 C语言中的字符串

    1.2 实际中

2. 标准库中的string类

    2.1 string类

    2.2 auto和范围for

    2.3 string类常用接口说明

3. string类的模拟实现

    3.1 经典的string类问题

        3.1.1 浅拷贝

       3.2.2 深拷贝

    3.2 string类模拟实现

1. 为什么学习string类?
    1.1 C语言中的字符串

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

    1.2 实际中

  在我们日常的刷题中,有关字符串的题目基本上是以string的形式出现的,并且在日常的生活当中,为了简单、方便快捷,基本上也都是使用的string,很少有人使用C标准库中的字符串操作函数。

2. 标准库中的string类
    2.1 string类

  string - C++ Reference (cplusplus.com)

  这里面有关于string类的详细说明,包括它的每个接口的功能以及接口的使用环境等。其中比较重要的接口有:operator=、iterators有关的begin、end的所有接口(自己实现时子需要实现begin、end即可,后面的rbegin和rend等理解即可)、size、resize、capacity、reserve、clear、empty、operator[]、operator+=、append、push_back、insert、erase、swap、c_str、find、find_first_of

    2.2 auto和范围for

auto关键字:

  在这里补充两个C++11的小语法,方便我们后面的学习

  ① 在早期C/C++中auto的含义是:使用auto修饰的变量,是具有自动存储器的局部变量,后来这个不重要了。C++11中,标准委员会变废为宝赋予了auto全新的含义即:auto不再是一个存储类型
指示符,而是作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期
推导而得,
也就是说,auto能够自动识别对象的类型

   用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须加&

   当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际只对第一个类型进行推导,然后用推导出来的类型定义其他变量。

  auto不能作为函数的参数,可以作为返回值,但是建议谨慎使用

  auto不能直接用来声明数组

  看到这里你可能觉得auto没什么作用,我知道我想要的是什么类型的我为什么还要它自动识别。别着急,后面你就会明白auto是有多好用。

范围for:

   对于一个有范围的集合而言,由程序员来说明循环的范围是多余的,有时候还会容易犯错误。因此C++11中引入了基于范围的for循环。for循环后的括号由冒号“ :”分为两部分:第一部分是范围内用于迭代的变量,第二部分则表示被迭代的范围,自动迭代,自动取数据,自动判断结束。

for(auto+变量 : 迭代范围)

{

        //循环体
}

  ② 范围for可以作用到数组和容器对象上进行遍历

  范围for看似非常智能很厉害,实际上底层就是迭代器(迭代器是什么后面会讲,此处记住即可)

    2.3 string类常用接口说明

1. string的常见构造函数:

2. string类对象的容量(Capacity)操作:

size(重点):返回字符串有效字符长度

length:返回字符串有效字符长度

capacity:返回所开空间总大小

empty(重点):检查字符串是否为空

clear(重点):仅删除数据,而不销毁空间

reserve(重点):为字符串预留一块空间,可以数据量小时可以省去开辟空间的消耗

rsize(重点):将有效的字符减为n(自己传)个,如果是增加,则多加的字符改为c(自己传)

注:

   size()与length()方法底层实现原理完全相同,引入size()的原因是为了与其他容器的接
口保持一致,一般情况下基本都是用size()。

   clear()只是将string中有效字符清空,不改变底层空间大小。

   resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不
同的是当字符个数增多时:resize(n)用0来填充多出的元素空间,resize(size_t n, char
c)用字符c来填充多出的元素空间。注意:resize在改变元素个数时,如果是将元素个数
增多,可能会改变底层容量的大小,如果是将元素个数减少,底层空间总大小不变。

  ④ reserve(size_t res_arg=0):为string预留空间,不改变有效元素个数,当reserve的参
数小于string的底层空间总大小时,reserver不会改变容量大小(Linux环境下会改变,但不会影响数据的存储)。

3. string类对象的访问及遍历操作:

operator[](重点):返回pos位置字符的引用(方便修改),const string类调用

begin+end(重点):begin获取字符串开头第一个字符的迭代器+end获取最后一个字符下一个位置的迭代器

//后面还有rbegin+rend、crbegin+crend、cbegin+cend等迭代器,这里不一一赘述

4. string类对象的修改操作:

push_back(重点):在字符串后尾插一个字符

append(重点):在字符串后尾插一个字符串

operator+=(重点):重载+=运算符,可以完成尾插操作

c_str(重点):返回字符串地址

find+npos(重点):从字符串pos位置开始往后查找所要字符,并返回其所在位置。如果遍历完字符串也找不到,则返回npos

rfind:从字符串pos位置开始往前查找所要字符,并返回其所在位置。如果找不到,则返回npos

substr:从字符串pos位置开始截取n个字符并返回

注:

  ① 在string尾部追加字符时,s.push_back(c) / s.append(1, c) / s += 'c'三种的实现方式差
不多,一般情况下string类的+=操作用的比较多,+=操作不仅可以连接单个字符,还可
以连接字符串。

  ② 对string操作时,如果能够大概预估到放多少字符,可以先通过reserve把空间预留
好,这样可以节剩开辟空间的效率消耗。

5. string类非成员函数

operator+:尽量少用,因为传值返回,导致深拷贝,导致效率降低

operator<<(重点):输入运算符重载,用于方便输出string字符串中的内容

operator>>(重点):输入运算符重载

getline(重点):获取一行字符串,遇到'\0'才会停止获取,在OJ的字符串题中很常用

relational operators(重点):大小比较,重载了各种类型的比较运算符

3. string类的模拟实现
    3.1 经典的string类问题
        3.1.1 浅拷贝

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

  例如:一个家庭中有两个孩子,但父母只买了一份玩具,两个孩子愿意一块玩,则万事大吉,万一不想分享就你争我夺,玩具损坏。

       3.2.2 深拷贝

  如果一个类中涉及到资源的管理,其拷贝构造函数、赋值运算符重载以及析构函数必须要显式给
出。一般情况都是按照深拷贝方式提供。

    3.2 string类模拟实现

//string.h头文件的声明

#pragma once


#include <iostream>
#include <assert.h>
using namespace std;


namespace gjk
{
    class string
    {
    public:

        typedef char* iterator;


        string(const char* s = "")
        {
            _str = new char[strlen(s) + 1];
            strcpy(_str, s);
            _size = strlen(s);
            _capacity = _size;
        }

        char& operator[](size_t pos)
        {
            assert(pos < _size);
            return _str[pos];
        }

        const char& operator[](size_t pos) const
        {
            assert(pos < _size);
            return _str[pos];
        }

        size_t size()
        {
            return _size;
        }

        const size_t size() const
        {
            return _size;
        }

        size_t capacity()
        {
            return _capacity;
        }

        const size_t capacity() const
        {
            return _capacity;
        }

        
        char* c_str()
        {
            return _str;
        }

        //迭代器
        iterator begin()
        {
            return _str;
        }

        const iterator begin() const
        {
            return _str;
        }

        iterator end()
        {
            return _str + _size;
        }

        const iterator end() const
        {
            return _str + _size;
        }

        ~string()
        {
            delete[] _str;
            _str = nullptr;
            _size = _capacity = 0;
        }

        //扩容
        void dilatancy(int newcapacity);
        //预留空间
        void reserve(size_t n);
        //改变有效字符数
        void rsize(size_t n, char ch = '\0');
        //尾插
        void push_back(char ch);
        //尾插字符串
        void append(const char* s);
        //指定插入字符
        void insert(size_t pos, char ch);
        //指定删除n字符
        void erase(size_t pos,size_t n = npos);
        //指定插入字符串
        void insert(size_t pos, const char* s);
        //清除数据
        void clear();
        //判空
        bool empty();

        //+=一个字符运算符重载
        string& operator+=(char ch);
        //+=字符串运算符重载
        string& operator+=(const char* s);


        //比较运算符重载
        bool operator==(const string& s);

        bool operator>(const string& s);

        bool operator<(const string& s);

        bool operator>=(const string& s);

        bool operator<=(const string& s);

        bool operator!=(const string& s);


        //找到字符第一次出现的位置
        int find(char ch,size_t pos = 0);

        //找到字符串第一次出现的位置
        int find(const char* s, size_t pos = 0);

    private:
        char* _str;
        size_t _size;
        size_t _capacity;

        const static size_t npos   = -1;
    };
}

//string.cpp文件的定义

#define _CRT_SECURE_NO_WARNINGS 1


#include "string.h"


namespace gjk
{
    //扩容
    void string::dilatancy(int newcapacity)
    {
        char* tmp = new char[newcapacity + 1];
        strcpy(tmp, _str);
        delete[] _str;
        _str = tmp;
        _capacity = newcapacity;
    }


    //预留空间
    void string::reserve(size_t n)
    {
        if (n > _capacity)
        {
            char* tmp = new char[n + 1];
            strcpy(tmp, _str);
            delete[] _str;
            _str = tmp;
            _capacity = n;
        }
    }

    //改变有效字符数
    void string::rsize(size_t n, char ch)
    {
        if (n <= _size)
        {
            _size = n;
            _str[_size] = '\0';
        }
        else
        {
            while (_size != n)
            {
                if (_size == _capacity)
                    dilatancy(_capacity == 0 ? 4 : 2 * _capacity);
                _str[_size++] = ch;
            }
            _str[_size] = '\0';
        }
    }

    //尾插
    void string::push_back(char ch)
    {
        if (_size == _capacity)
            dilatancy(_capacity == 0 ? 4 : 2 * _capacity);
        _str[_size++] = ch;
        _str[_size] = '\0';
    }


    //尾插字符串
    void string::append(const char* s)
    {
        int len = strlen(s);
        if (_size + strlen(s) > _capacity)
            dilatancy(_size + len > 2 * _capacity ? _size + len : 2 * _capacity);
        strcpy(_str + _size, s);
        _size += len;
    }


    //指定插入字符
    void string::insert(size_t pos, char ch)
    {
        assert(pos <= _size);
        if (_size == _capacity)
            dilatancy(_capacity == 0 ? 4 : 2 * _capacity);
        size_t end = _size + 1;
        while (end > pos)
        {
            _str[end] = _str[end - 1];
            end--;
        }
        _str[pos] = ch;
        _size++;
    }


    //指定删除n个字符
    void string::erase(size_t pos,size_t n)
    {
        assert(pos < _size);
        if (n >= _size - pos||n == npos)
        {
            _str[pos] = '\0';
            _size -= (_size - pos);
        }
        else
        {
            size_t end = pos + n;
            while (end <= _size)
            {
                _str[pos++] = _str[end++];
            }
            _size -= n;
        }
    }

    //指定插入字符串
    void string::insert(size_t pos, const char* s)
    {
        assert(pos <= _size);
        int len = strlen(s);
        if (_size + strlen(s) > _capacity)
            dilatancy(_size + len > 2 * _capacity ? _size + len : 2 * _capacity);
        size_t end = _size + len + 1;
        while (end - len > pos)
        {
            _str[end] = _str[end - len - 1];
            end--;
        }
        memcpy(_str + pos, s, len);
        _size += len;
    }


    //清除数据
    void string::clear()
    {
        _str[0] = '\0';
        _size = 0;
    }


    //判空
    bool string::empty()
    {
        return _size == 0;
    }


    //+=一个字符运算符重载
    string& string::operator+=(char ch)
    {
        push_back(ch);
        return *this;
    }


    //+=字符串运算符重载
    string& string::operator+=(const char* s)
    {
        append(s);
        return *this;
    }


    //比较运算符重载
    bool string::operator==(const string& s)
    {
        return strcmp(_str, s._str) == 0;
    }

    bool string::operator>(const string& s)
    {
        return strcmp(_str, s._str) > 0;
    }


    bool string::operator<(const string& s)
    {
        return !(*this == s || *this > s);
    }


    bool string::operator>=(const string& s)
    {
        return !(*this < s);
    }


    bool string::operator<=(const string& s)
    {
        return !(*this > s);
    }


    bool string::operator!=(const string& s)
    {
        return !(*this == s);
    }

    //找到字符第一次出现的位置
    int string::find(char ch,size_t pos)
    {
        assert(pos < _size);
        while (_str[pos] != ch && pos < _size)
        {
            pos++;
        }
        if (pos == _size)
            return -1;
        return pos;
    }


    //找到字符串第一次出现的位置
    int string::find(const char* s, size_t pos)
    {
        assert(pos < _size);
        int len = strlen(s);
        while (_str[pos] != s[0] && pos < _size)
        {
            pos++;
        }
        if (pos == _size||_size-pos < len)
            return -1;
        int ret = memcmp(_str + pos, s, len);
        if (!ret)
            return pos;
        return -1;
    }
}

   

                                                 创作不易,点个赞呗,蟹蟹啦~             

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

day07:用户下单、订单支付

文章目录 地址薄相关相关代码需求分析和设计代码书写 用户下单需求分析和设计代码开发 订单支付微信支付介绍微信支付准备工作如何保证数据安全&#xff1f;如何调用到商户系统 地址薄相关相关代码 需求分析和设计 产品原型接口设计数据库设计 代码书写 地址薄相关代码都是单…

【unity 新手教程 001/100】安装与窗口布局介绍

欢迎关注 、订阅专栏 【unity 新手教程】谢谢你的支持&#xff01;&#x1f49c;&#x1f49c; Unity下载与安装 &#x1f449;点击跳转详细图文步骤&#xff1a;Unity Hub Unity 编辑器 窗口布局&#xff1a; Hierarchy: 层级窗口 | 默认 Sample Scene (main camera、direc…

三星Unpacked发布会即将举行:有新款折叠屏手机,还有智能戒指

随着7月的脚步渐近&#xff0c;科技界的目光再次聚焦于三星&#xff0c;它即将在法国巴黎举办今年的第二场Unpacked发布会。这不仅是一场新品的展示&#xff0c;更是三星对创新科技的一次深刻诠释。 从Galaxy Z Fold 6的全新设计&#xff0c;到Galaxy Z Flip 6的显著升级&…

MySQL数据库练习(四)

1.建库建表 # 创建数据库 create database mydb15_indexstu;# use mydb15_indexstu;# 学生表student&#xff0c;定义主键&#xff0c;姓名不能重名&#xff0c;性别只能输入男或女&#xff0c;所在系的默认值是“计算机”&#xff0c;结构如下:student(Sno 学号&#xff0c;…

C#中的线性表

什么是线性表 线性表是最简单、最基本、最常用的数据结构。线性表是线性结构的抽象(Abstract),线性结构的特点是结构中的数据元素之间存在一对一的线性关系。这种一对一的关系指的是数据元素之间的位置关系,即:(1)除第一个位置的数据元素外,其它数据元素位置的前面都只有一个数…

基于python的京东VR眼镜口碑情感分析,包括lda和情感分析

第1章 绪论 1.1选题背景 在当今科技发展迅速的时代&#xff0c;虚拟现实&#xff08;VR&#xff09;技术作为一种前沿的数字体验方式受到越来越多人的关注。京东作为中国领先的电商平台&#xff0c;推出的VR眼镜备受消费者关注。通过对京东VR眼镜口碑进行情感分析&#xff0c…

2022 年中高职组“网络安全”赛项-海南省省竞赛任务书-1-B模块-B-4Web渗透测试

前言 本章节我将尝试操作B-4模块的渗透测试&#xff0c;搭建环境很难&#xff0c;还望大家点点赞多多支持&#xff01; 任务概览 最后4、5、6有一定的难度。 环境要求 kali Linux192.168.41.2Web服务器&#xff08;假设为PYsystem 2020 模拟平台&#xff09;192.168.41.7交换…

AGV平面坐标系变换公式及实例

1、AGV坐标系简介 如上图&#xff0c;小车前后对角是有激光雷达的&#xff0c;其坐标系称为激光坐标系&#xff0c;采用极坐标系体现。中间为车体坐标系&#xff0c;激光坐标系相对于车体坐标系关系不变&#xff1b;左下角是地图坐标系&#xff0c;小车扫图后&#xff0c;建立的…

PCIE的GT计算

在PCIe总线中&#xff0c;使用GT(Gigatransfer)计算PCIe链路的峰值带宽。GT是在PCIe链路上传递的峰值带宽&#xff0c;其计算公式为总线频率数据位宽2。

JMeter的使用方法及https的使用方法

软件安装&#xff1a; 参考链接&#xff1a;JMeter 下载安装及环境配置&#xff08;包含jdk1.8安装及配置&#xff09;_jmeter5.2.1需要什么版本的jdk-CSDN博客 前置知识储备&#xff1a; Https请求的案例: JMeter的第一个案例 增加线程数 线程&#xff08;thread&#xff…

视频行业(监控,直播,会议,视频通话)痛点,随时接入,异构融合,以OvMeet视频会议为中心解决企业视频应用完美解决方案

近年来随着网络的普及及音视频技术的不断发展&#xff0c;以全球化、网络化、智能化未趋势的办公方式越来越受到各行各业的青睐。视频会议解决方案的应用转往多种交互式视频应用&#xff0c;如转往视频接入融合&#xff0c;调度与管理、日常沟通、工作部署、紧急救援、作战指挥…

Vue3 SvgIcon组件开发

在前面自定义tree组件继续功能迭代前&#xff0c;我们先开发一个通用的ScgIcon组件&#xff0c;用于后续组件模板中小图标的展示。 引入iconfont 官网&#xff1a;https://www.iconfont.cn/ 选取图标进行下载&#xff0c;只取iconfont.js文件 在prettier中忽略该文件&#x…

NS4890C 2.4W 单声道AB类音频放大器

前言&#xff1a; 3W单声道关断模式音频功率放大器AD4150B NS4890C 国产小功放&#xff0c;性价比高&#xff0c;体积小MSOP8封装 参考价格0.2元 NS4890C 2.4W 单声道AB类音频放大器 1 产品特点 电压范围&#xff1a;3.0V-5.0V 输出功率&#xff1a;1.56WRL8Ω/THDN10% 关机…

基于Python的帕金森病人步态分析

目录 摘要一、引言1.背景知识2.实验目的和意义 二、实验方法1.实验环境2.实验步骤2.1 生成信号&#xff0c;进行手动傅里叶变换以及内置 FFT 函数傅里叶变换2.2 进行手动傅里叶变换以及内置 FFT 函数傅里叶变换2.3 基于傅里叶变换的步态信息分析2.4 基于傅里叶变换的卷积分析 3…

2024新版 黑马程序员《C++零基础入门》笔记——入门09 cout打印输出

1.cout打印输出 2.代码练习 #include "iostream" using namespace std;int main() {cout << "I love Libby!" << endl;cout << 10 << endl;cout << "I am 10" << "years old." << endl;re…

Marin说PCB之1000-BASE-T1上的共模电感的选型知多少?

单板上的电子原件的物料的升级和替代想必对我们做这些做硬件的同志们并不陌生吧&#xff0c;之前遇到最多情况的就是一些主芯片上的电容可能由于电源完整性得原因需要替换成一个性能好一些物料&#xff0c;这个是比较常见的操作&#xff0c;一般做法都是仿真的同事自己把两颗电…

初试Ollama本地大模型

准备工作 机器配置&#xff1a; CPUi5-10400内存16GB硬盘SSD 480GB显卡GTX 1660 系统&#xff1a;Ubuntu 18.04 Server NVIDIA驱动安装 - 下载 驱动下载地址&#xff1a;https://www.nvidia.cn/geforce/drivers/ - 获取下载链接 GTX 1660驱动下载链接&#xff1a;https://…

Django执行ORM时打印SQL语句

settings中添加LOGGING相关日志配置 LOGGING {version: 1,disable_existing_loggers: False,handlers: {console:{level:DEBUG,class:logging.StreamHandler,},},loggers: {django.db.backends: {handlers: [console],propagate: True,level:DEBUG,},}}批量查询DEMO&#xf…

硅纪元视角 | 类器官智能OI技术实现将人脑植入机器人

在数字化浪潮的推动下&#xff0c;人工智能&#xff08;AI&#xff09;正成为塑造未来的关键力量。硅纪元视角栏目紧跟AI科技的最新发展&#xff0c;捕捉行业动态&#xff1b;提供深入的新闻解读&#xff0c;助您洞悉技术背后的逻辑&#xff1b;汇聚行业专家的见解&#xff0c;…

Mysql基础速过

一、数据库相关概念 1.1 相关概念 名称全称简称数据库存储数据的仓库、数据是有组织的进行存储DataBase(DB)数据库管理系统操作和管理数据库的大型软件DataBase Management System(DBMS)SQL操作关系型数据库的编程语言&#xff0c;定义了一套操作关系型数据库统一标准Structu…