[STL]string的使用+模拟实现

news2024/11/25 14:48:24

[STL]string的使用+模拟实现

文章目录

      • [STL]string的使用+模拟实现
        • 一、STL
          • 1.什么是STL
          • 2.如何学习STL
        • 二、string
          • 1.string类的介绍
          • 2.string的常用接口
            • string的构造
            • string的迭代器
            • string的容量操作
            • string的访问
            • string的修改
            • string的其他接口
            • string的非成员函数接口
        • 三、string的模拟实现
        • string.h
        • test.cpp

一、STL

1.什么是STL

1.STL (standard template libaray - 标准模板库):是C++标准库的重要组成部分,不仅是一个可复用的组件库,而且是一个包罗数据结构与算法的软件框架

在这里插入图片描述

它包含了vector /stack/queue/priority_queue/list/set/map等。

在这里插入图片描述

我们在使用C++时不必再需要用轮子时,现场手搓出一个轮子了。

2.如何学习STL

1.我们进入CPP,即可开始学习。

我个人认为这个网站做的比C++的官网更好,使用更加方便。(一般使用旧版更好,新版不登录不能进行搜索)

2.我们也可以看书进行学习,例如《STL源码剖析》或者《C++ primer》。

二、string

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

  • 所以C++提供了一个string类,通过实现string的各种函数接口(插入、删除、清空等等),来帮助我们更方便的对字符进行操作。

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

string并不属于STL,string比STL的诞生还要早。

2.string的常用接口
string的构造

在这里插入图片描述

  • 还有一个拷贝构造函数

string(const string& s)

在这里插入图片描述

string的迭代器

Iterator是C++中定义的迭代器,我们在这里(string)简单先理解为指针。

typedef char* iterator;

在这里插入图片描述

  • begin() : 返回第一个字符位置的迭代器
  • end() : 返回最后一个字符的下一个位置(‘\0’)的迭代器

反向迭代器

  • rbegin() : 返回指向最后一个字符的下一个位置(‘\0’)的迭代器
  • rend() : 返回指向第一字符位置的迭代器

const 迭代器(为了满足const对象的调用)

  • cbegin() : 返回第一个字符位置的迭代器

  • cend() : 返回最后一个字符的下一个位置(‘\0’)的迭代器

在这里插入图片描述

string的容量操作

在这里插入图片描述

  • size : 返回字符串长度
  • capacity : 返回字符串容量
  • empty : 返回字符串是否为空

  • resize : 调整字符串大小,但分为3种情况

在这里插入图片描述

1.n < str.size(),把原来的size大小改为n

2.str.size() < n < str.capacity(), 修改字符串的size为n, 若有字符c的输入,将大于size小于capacity的部分设置为字符c

3.n > str.capacity(), 将原数组扩容到n, 若有字符c输入,则将size后面的部分全部设置为字符c

在这里插入图片描述


  • reserve : 改变字符串容量

n > str.capacity(), 将字符串的capacity扩容到n

n <= str.capcaity(), 按编译器规则进行修改容量。(vs2019不进行修改)

reserve只会改变字符串容量,不会改变字符串的size大小。

在这里插入图片描述


  • clear : 清空字符串

在这里插入图片描述

string的访问

在这里插入图片描述

operator[](最常用)

[]进行运算符重载,实现对string对象的随机访问。

在这里插入图片描述

string的修改

在这里插入图片描述

  • push_back : 尾插一个字符
  • pop_back : 尾删一个字符
  • operator+= : 运算符+=重载

相比于push_back,在string中我们更喜欢使用+=进行插入字符。

它可以插入插入一个字符或者插入一个字符串或者插入一个字符数组
在这里插入图片描述
在这里插入图片描述


  • append : 类似于+=, 在字符串尾部追加数据

在这里插入图片描述

常用的有:

1.直接追加字符串

2.追加字符串的第几位到第几位

3.追加几个字符c

在这里插入图片描述


  • insert : 插入数据

在这里插入图片描述

常用的:

1.在某个位置插入字符串

2.在某个位置插入几个字符c

3.在某个位置插入数组

在这里插入图片描述


  • erase : 删除数据

在这里插入图片描述

常用:从pos位置删除到某个位置。

在这里插入图片描述

ps: 若只传起始位置pos,则缺省值npos为-1(npos为无符号数,则他是整形的最大值,erase会一直删除直到遇到’\0’)。


  • swap

交换两个字符串的内容。(包括字符数组、有效数据个数,及容量大小)
在这里插入图片描述
在这里插入图片描述


string的其他接口
  • c_str : 返回C形式的字符串
  • find : 返回字符或者字符串在string对象中首次出现的位置
  • rfind : 返回字符或者字符串在string对象中首次出现的位置(从最后一个字符开始找)
  • substr : 将从pos位置到len个长度构建一个新string对象并返回

在这里插入图片描述


string的非成员函数接口
  • operator>>

在这里插入图片描述

  • operator<<

在这里插入图片描述

  • getline : 插入含有空格的字符

我们在插入时,遇到一个空格、换行、或者回车,cin就会停止读取。

我们在插入必须含有空格的字符时,我们应该使用getline(cin, str)

而且我们还可以设置终止字符。
在这里插入图片描述

在这里插入图片描述

三、string的模拟实现

string.h

#pragma once
#include <iostream>
#include <string.h>
#include <assert.h>
using namespace std;
namespace myString
{
    class string
    {
        friend ostream& operator<<(ostream& out, const myString::string& s)
        {
            for (size_t i = 0; i < s.size(); i++)
            {
                out << s[i];
            }
            return out;
        }

        friend istream& operator>>(istream& in, myString::string& s)
        {
            s.clear();
            char buff[128] = { '\0' };
            size_t i = 0;
            char ch = in.get();
            while (ch != ' ' && ch !='\n')
            {
                if (i == 127)
                {
                    s += buff;
                    i = 0;
                }
                buff[i++] = ch;
                ch = in.get();
            }
            if (i > 0)
            {
                buff[i] = '\0';
                s += buff;
            }
            return in;
        }

    public:

        typedef char* iterator;

    public:

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

        string(const string& s)
            :_str(nullptr)
            ,_size(0)
            ,_capacity(0)
        {
            string tmp(s._str);
            swap(tmp);
        }

        /*string& operator=(const string& s)
        {
            if (this != &s)
            {
                char* tmp = new char[s._capacity + 1];
                strcpy(tmp, s._str);

                delete[] _str;
                _str = tmp;

                _size = s._size;
                _capacity = s._capacity;
            }

            return *this;
        }*/

        string& operator=(string s)
        {
            swap(s);
            return *this;
        }

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



        //

        // iterator

        iterator begin()
        {
            return _str;
        }

        iterator end()
        {
            return _str + _size;
        }

        /

        // modify

        void push_back(char c)
        {
            if (_size == _capacity)
            {
                size_t NewCapacity = _capacity == 0 ? 4 : _capacity * 2;
                reserve(NewCapacity);
            }
            _str[_size] = c;
            _size++;
            _str[_size] = '\0';
        }

        string& operator+=(char c)
        {
            push_back(c);
            return *this;
        }

        void append(const char* str)
        {
            size_t len = strlen(str);
            if (_size + len > _capacity)
            {
                reserve(_size + len);
            }
            strcpy(_str + _size, str);
            _size += len;
        }

        string& operator+=(const char* str)
        {
            append(str);
            return *this;
        }

        void clear()
        {
            _size = 0;
            _str[_size] = '\0';
        }

        void swap(string& s)
        {
            std::swap(_str, s._str);
            std::swap(_size, s._size);
            std::swap(_capacity, s._capacity);
        }

        const char* c_str()const
        {
            return _str;
        }

        /

        // capacity

        size_t size()const
        {
            return _size;
        }

        size_t capacity()const
        {
            return _capacity;
        }

        bool empty()const
        {
            return _size == 0;
        }

         void resize(size_t n, char c = '\0')
         {
             if (n > _size)
             {
                 reserve(n);

                 for (size_t i = _size; i < n; i++)
                 {
                     _str[i] = c;
                 }
                 _size = n;
                 _str[_size] = '\0';
             }
             else
             {
                 _str[n] = '\0';
                 _size = n;
             }
         }

        void reserve(size_t n)
        {
            if (n > _capacity)
            {
                char* tmp = new char[n + 1];
                strcpy(tmp, _str);
                delete[] _str;
                _str = tmp;
                _capacity = n;
            }
        }

        /

        // access

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

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

        // 返回c在string中第一次出现的位置

        size_t find(char c, size_t pos = 0) const
        {
            assert(pos < _size);
            for (size_t i = pos; i < _size; i++)
            {
                if (_str[i] == c)
                    return pos;
            }
            return npos;
        }

        // 返回子串s在string中第一次出现的位置

        size_t find(const char* s, size_t pos = 0) const
        {
            assert(pos < _size);
            const char* ptr = strstr(_str+pos, s);
            if (ptr == nullptr)
                return npos;
            else
                return _str - ptr;
        }

        // 在pos位置上插入字符c/字符串str,并返回该字符的位置

        string& insert(size_t pos, char c)
        {
            if (_size == _capacity)
            {
                size_t NewCapacity = _capacity == 0 ? 4 : _capacity * 2;
                reserve(NewCapacity);
            }
            size_t end = _size + 1;
            while (end > pos)
            {
                _str[end] = _str[end - 1];
                --end;
            }
            _str[pos] = c;
            ++_size;
            return *this;
        }

        string& insert(size_t pos, const char* str)
        {
            size_t len = strlen(str);
            if (_size + len > _capacity)
            {
                reserve(_size + len);
            }
            size_t end = _size + len;
            while (end > pos + len - 1)
            {
                _str[end] = _str[end - len];
                --end;
            }
            strncpy(_str + pos, str, len);
            _size += len;
            return *this;
        }



        // 删除pos位置上的元素,并返回该元素的下一个位置

        string& erase(size_t pos, size_t len = npos)
        {
            assert(pos < _size);
            if (len == npos || pos + len > _size)
            {
                _str[pos] = '\0';
                _size = pos;
            }
            else
            {
                strcpy(_str + pos, _str + pos + len);
                _size -= len;
            }
            return *this;
        }

    private:
        char* _str;
        size_t _capacity;
        size_t _size;
        const static size_t npos = -1;
    };
        void test1()
        {
            string s1("hello world");
            std::cout << s1.c_str() << std::endl;

            for (size_t i = 0; i < s1.size(); ++i)
            {
                s1[i]++;
            }
            std::cout << s1.c_str() << std::endl;

            string::iterator it1 = s1.begin();
            while (it1 != s1.end())
            {
                (*it1)--;

                ++it1;
            }
            std::cout << s1.c_str() << std::endl;

            for (auto ch : s1)
            {
                std::cout << ch << " ";
            }
            std::cout << std::endl;
        }

        void test2()
        {
            string s1("hello");
            s1 += ' ';
            s1 += '!';
            s1 += '!';

            s1 += "world hello world";

            cout << s1.c_str() << endl;

            string s2;
            s2 += 'x';

            cout << s2.c_str() << endl;
        }
        void test3()
        {
            string s1("helloworld");
            cout << s1.c_str() << endl;

            s1.insert(5, ' ');
            cout << s1.c_str() << endl;

            s1.insert(0, 'x');
            cout << s1.c_str() << endl;

            string s2("helloworld");
            cout << s2.c_str() << endl;
            s2.insert(5, " + ");
            cout << s2.c_str() << endl;

            s2.insert(0, "hello ");
            cout << s2.c_str() << endl;

            s2.insert(0, "x");
            cout << s2.c_str() << endl;

            string s3;
            s3.insert(0, "");
            cout << s3.c_str() << endl;
        }
        void test4()
        {
            string s1("hello hello world");
            s1.erase(0, 6);
            cout << s1.c_str() << endl;

            s1.erase(5);
            cout << s1.c_str() << endl;
        }
        void test5()
        {
            string s1("hello world");
            s1.resize(5);
            cout << s1.size() << endl;
            cout << s1.capacity() << endl;
            cout << s1.c_str() << endl << endl;

            string s2("hello world");
            //s2.resize(15);
            s2.resize(15, 'x');
            cout << s2.size() << endl;
            cout << s2.capacity() << endl;
            cout << s2.c_str() << endl << endl;

            string s3("hello world");
            s3.resize(20, 'x');
            cout << s3.size() << endl;
            cout << s3.capacity() << endl;
            cout << s3.c_str() << endl << endl;
        }
        void test6()
        {
            string s1("hello world");
            cout << s1 << endl;
            cout << s1.c_str() << endl;

            s1.insert(5, '\0');
            cout << s1.size() << endl;
            cout << s1.capacity() << endl;

            cout << s1 << endl;
            cout << s1.c_str() << endl;
            cin >> s1;
            cout << s1 << endl;


            string s2;
            cin >> s2;
            cout << s2 << endl;

            string s3;
            cin >> s3;
            cout << s3 << endl;
        }
        void test7()
        {
            string s1("hello world");
            string s2(s1);

            cout << s1 << endl;
            cout << s2 << endl;

            string s3("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
            s1 = s3;
            cout << s1 << endl;
            cout << s3 << endl;
        }
    }

test.cpp

#include "myString.h"

int main()
{
	//myString::test1();
	/*myString::test2();*/
	/*myString::test3();*/
	/*myString::test4();*/
	/*myString::test5();*/
	//myString::test6();
	myString::test7();
	return 0;
}

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

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

相关文章

Node【七】初识Express框架

文章目录&#x1f31f;前言&#x1f31f;Express框架&#x1f31f;1.什么是框架&#x1f31f;2.express安装&#x1f31f;3.创建web服务基本遵循之前的四个步骤&#xff1a;&#x1f31f;4.路由&#x1f31f; 由 &#xff1a;请求方式请求路径&#xff08;1&#xff09;get发送…

JAVA+SQL离散数学题库管理系统的设计与开发

题库、试卷建设是教学活动的重要组成部分&#xff0c;传统手工编制的试卷经常出现内容雷同、知识点不合理以及笔误、印刷错误等情况。为了实现离散数学题库管理的信息化而开发了离散数学题库管理系统。 该系统采用C/S 模式&#xff0c;前台采用JAVA&#xff08;JBuilder2006&am…

面试官:自动化测试都没弄明白,你怎么敢来面试的?

最近看了很多简历&#xff0c;很多候选人年限不小&#xff0c;但是做的都是一些非常传统的项目&#xff0c;想着也不能通过简历就直接否定一个人&#xff0c;何况现在大环境越来 越难&#xff0c;大家找工作也不容易&#xff0c;于是就打算见一见。 在沟通中发现&#xff0c;由…

全国青少年信息素养大赛图形化编程初赛·模拟二卷,含答案解析

全国青少年电子信息智能创新大赛 图形化编程选做题模拟二卷 一、单选题 1. 下图中的程序执行一次之后,“我的变量”最终的值是?( ) A、0或者1 B、true或者false C、包含或者不包含 D、成立或者不成立

纯虚函数和抽象类

什么时候使用纯虚函数: 某些类,在现实角度和项目实现角度,都不需要实例化(不需要创建它的对象),这个类中定义的某些成员函数,只是为了提供一个形式上的借口,准备让子类来做具体化的实现,此时,这个方法就可以定义为"纯虚函数",包含纯虚函数的类,就称为抽象类. 纯虚函…

token详解

token详解前言什么是token&#xff1f;为什么要使用token&#xff1f;那么如何使用token呢&#xff1f;使用Token进行身份验证和授权的过程具体步骤项目上如何运用的tokentoken过期了什么办&#xff1f;总结升华前言 本篇博客主要从什么是token&#xff1f;为什么要使用token&…

C++ 图系列之基于有向无环图的拓扑排序算法

1. 前言 有向无环图&#xff0c;字面而言&#xff0c;指图中不存在环(回路)&#xff0c;意味着从任一顶点出发都不可能回到顶点本身。有向无环图也称为 DAG&#xff08;Directed Acycline Graph&#xff09;。 有向无环图可用来描述顶点之间的依赖关系&#xff0c;依赖这个概…

MLX90640 热成像 STM32

点击此处了解详情点击此处了解详情点击此处了解详情点击此处了解详情点击此处了解详情 1、描述 这是一款手持式多功能热像仪&#xff0c;小巧轻便&#xff0c;搭载3.2英寸TFT显示屏、MLX90640热红外探头&#xff0c;锂电池供电&#xff0c;可以在各种场合使用&#xff0c;温度…

( “树” 之 DFS) 572. 另一棵树的子树 ——【Leetcode每日一题】

572. 另一棵树的子树 给你两棵二叉树 root 和 subRoot 。检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树。如果存在&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 二叉树 tree 的一棵子树包括 tree 的某个节点和这个节点的所有后代节点。tr…

Densely Connected Convolutional Networks(引言翻译(有选择性))

翻译得有可能会不太专业&#xff0c;望见谅的同时&#xff0c;如果有些地方翻译错了&#xff0c;欢迎批评指正&#xff01; as information about the input or gradient passes through many layers, it can vanish and "wash out" by the time it reaches the end …

淄博烧烤、洛阳汉服......爆火,揭秘实体店客流爆满的秘诀!

淄博烧烤、云南泼水、洛阳穿越...... 沉寂了3年后&#xff0c;线下实体消费终于又开始火热起来&#xff0c;临近五一小长假&#xff0c;国内外旅游订单出现井喷式增长&#xff0c;线下消费持续迎来新一轮的高峰。 而这些热点&#xff0c;也带动了周边很多相关的实体店&#xff…

美团外卖平台的部分外卖 SPU数据实操练习

一、环境要求 Hadoop hive spark hbase开发环境 开启hadoop&#xff1a;start-all.sh开启zookeeper&#xff1a;zkServer.sh start开启hive&#xff1a;nohup hive --service metastore &nohup hive --service hiveserver2 & 打开hive界面&#xff1a;beeline -u j…

Ubuntu16.04安装NCNN和Opencv

一、安装NCNN 官网&#xff1a;NCNN官方文档 On Debian, Ubuntu or Raspberry Pi OS, you can install all required dependencies using: 首先安装NCNN的依赖项&#xff0c;根据官网安装以下依赖项。 sudo apt install build-essential git cmake libprotobuf-dev protobuf-…

dc-4靶机渗透

1.信息搜集&#xff0c;扫描存活主机&#xff0c;扫描端口&#xff0c;服务,发现开放80&#xff0c;22端口&#xff0c;cms没有看到 nmap 192.168.85.0/24 nmap -p1-66535 192.168.85.175 nmap -sv 192.168.85.1752.访问网站&#xff0c;发现登录框&#xff0c;根据提示&#…

360安全卫士 - 设置技巧 / 关闭广告

360安全卫士 - 设置技巧 / 关闭广告前言同步设置基本设置弹窗设置开机小助手安全防护中心漏洞修复木马查杀功能大全管理360文件夹游戏管家健康助手前言 360安全卫士是一款免费的PC安全软件&#xff0c;拥有垃圾清理、病毒查杀、启动项管理等功能。虽然有一些广告&#xff0c;但…

【Python】python技能树之包含元祖的列表升降序

文章目录前言一、实际操作二、使用步骤总结前言 大家都知道&#xff0c;在Python里面可以使用.sort方法或者sorted函数对各种数据进行排序&#xff0c;例如&#xff1a; 一、实际操作 a [2, 3, 1, 9, 3, 7, 4] a.sort() b [2, 3, 1, 9, 3, 7, 4] c sorted(b, reverseTrue…

Linux中的网络

文章目录一 、查看网络配置1.2 route命令—查看路由条目1.3 1.3hostname命令—查看主机名称1.4netstat命令—查看网络连接情况二 、测试网络连接2.1 ping 命令2.2 traceroute命令—跟踪数据包的路由途径2.3 mtr—动态跟踪网络2.4 nslookup命令—测试域名解析三 、使用网络配置命…

迎难而上,阿里高频考点2023Java岗面试突击手册

上周我接到一位粉丝的私信说目前互联网形势实在对他太不友好&#xff0c;感觉自己每个技术栈都会一点&#xff0c;但不是完全精通。基本二面三面的时候就挂了&#xff0c;已经完全不知道该朝哪个方向努力了&#xff0c;希望可以给他一些建议和方法指导。那么&#xff0c;本次就…

[golang gin框架] 20.Gin 商城项目-商品模块功能

一.商品模块数据表ER图关系分析商品模块数据表相关功能关系见:[golang gin框架] 16.Gin 商城项目-商品模块数据表ER图关系分析二.商品相关界面展示商品列表该商品列表有如下功能1.增加商品按钮:跳转到增加商品页面2.搜索功能:输入商品名称,点击搜索3.修改商品字段(上架,精品,新…

软件测试入门第一步:编写测试报告

什么是测试报告&#xff1f; 1、说明&#xff1a;是指把测试的过程和结果写成文档&#xff0c;对发现的问题和缺陷进行分析&#xff0c;为纠正软件的存在的质量问题提供依据&#xff0c;同时为软件验收和交付打下基础。 ps. 【测试过程和测试结果的分析报告&#xff0c;以及上线…