STL-string类的使用及其模拟实现

string类的使用

       string 类是 C++ 标准库提供的用于处理字符串的类,它相比 C 语言中的字符串处理函数更为高级、灵活和安全。

       string 类提供了丰富的成员函数和操作符,用于处理字符串的拼接、查找、替换、截取、插入等操作。string 类自动处理字符串的内存分配和释放,不会像 C 语言中的字符数组那样容易出现缓冲区溢出等安全问题。使用 string 类能够有效避免许多与字符数组相关的安全漏洞。string 类是 C++ 标准模板库(STL)中的一部分,学习 string 类也是为了更好地理解和使用 STL 的其他组件,如向量、链表、映射等。

string类对象的常见构造:

string类对象的容量接口:

string类对象的元素访问:

string类对象的Iterators(迭代器)接口:

string类对象的修改:

npos
     npos 是 std::string 类中的一个静态常量成员,用于表示无效或未找到的位置。它是一个特殊的 std::string::size_type 类型的常量,通常被定义为 std::string::npos,其值在不同的编译器和实现中可能不同,但通常被设为 -1 或一个非常大的值,用于表示在字符串中未找到指定的子串或字符。

    npos 主要用于字符串查找操作,比如在使用 find()、rfind()等成员函数时,当查找失败或没有找到指定的子串或字符时,这些函数通常会返回 std::string::npos 来表示无效的位置。

注意:npos 的值是一个非常大的无符号整数,因此在比较 std::string::size_type 类型的值时,应使用无符号类型的比较方式,避免可能出现的错误。比如使用 pos != std::string::npos 来判断是否找到了指定的子串或字符。

string类的模拟实现

      std::string 是一个类模板,模拟实现它需要深入理解类和对象的概念,包括构造函数、析构函数、成员函数、成员变量等。通过实现一个类似 std::string 的类,你可以更好地理解类的设计和使用。

class string
{
public:
    typedef char* iterator;
    typedef const char* const_iterator;
    iterator begin()
    {
        return _str;
    }
    iterator end() {
        return _str + _size;
    }
    iterator begin() const
    {
        return _str;
    }
    iterator end() const{
        return _str + _size;
    }
    /*string() 
        :_str(new char[1])
        ,_size(0)
        ,_capacity(0)
    {
        _str[0] = '\0';
    }*/
  
    string(const char* str = "")
        :_size(strlen(str))//不包括'\0'的大小
    {
        _capacity = _size==0 ? 3 : _size;
        _str = new char[_capacity + 1];
        strcpy(_str, str);
    }
    string(const string& s)
        :_size(s._size)
        ,_capacity(s._capacity)
    {
        _str = new char[s._capacity+1];
        strcpy(_str, s._str);
    }
    // 传统写法
    string& operator=(const string& s) {
        if (this != &s) {
            /*delete[] _str;
            _str = new char[s._capacity + 1];
            strcpy(_str, s._str);
            _size = s._size;
            _capacity = s._capacity;
            return *this;*/

            char* tmp = new char[s._capacity + 1];
            strcpy(tmp, s._str);
            delete[] _str;
            _str = tmp;

            _size = s._size;
            _capacity = s._capacity;
        }
    }
    // 现代写法 
    void swap(string& tmp)
    {
        ::swap(_str, tmp._str);
        ::swap(_size, tmp._size);
        ::swap(_capacity, tmp._capacity);
    }
    string(const string& s)
        :_str(nullptr)
        , _size(0)
        , _capacity(0)
    {
        string tmp(s._str);
        swap(tmp);
    }
    ~string() {
        delete[] _str;
        _str = nullptr;
        _size = _capacity = 0;
    }
    string to_string(int value)
    {
        bool flag = true;
        if (value < 0)
        {
            flag = false;
            value = 0 - value;
        }

        string str;
        while (value > 0)
        {
            int x = value % 10;
            value /= 10;

            str += ('0' + x);
        }

        if (flag == false)
        {
            str += '-';
        }

        std::reverse(str.begin(), str.end());
        return str;
    }
    const char* c_str() {
        return _str;
    }
    const char& operator[](size_t pos) const {
        assert(pos < _size);
        return _str[pos];
    }
    char& operator[](size_t pos) {
        assert(pos < _size);
        return _str[pos];
    }
    size_t size() const{
        return _size;
    }
    size_t capacity() const {
        return _capacity;
    }

    //string& operator=(const string& s)
    //{
    //    if (this != &s)
    //    {
    //        //string tmp(s._str);
    //        string tmp(s);
    //        swap(tmp); // this->swap(tmp);
    //    }

    //    return *this;
    //}
    string& operator=(const string& s)
    {
        if (this != &s) //防止自己给自己赋值
        {
            string tmp(s); //用s拷贝构造出对象tmp
            swap(tmp); //交换这两个对象
        }
        return *this; //返回左值(支持连续赋值)
    }
    //不修改成员变量数据的函数,最好都加上const
    bool operator>(const string& s) const {
        return strcmp(_str, s._str) > 0;
    }
    bool operator==(const string& s) const {
        return strcmp(_str, s._str) == 0;
    }
    bool operator>=(const string& s) const {
        return *this > s || *this == s;
    }
    bool operator<(const string& s) const {
        //return strcmp(_str, s._str) < 0;
        return !(*this >= s);
    }
    bool operator<=(const string& s) const {
        //return *this < s || *this == s;
        return !(*this > s);
    }
    //扩容
    void reserve(size_t n) {
        if (n > _capacity) {
            char* tmp = new char[n + 1];
            strcpy(tmp, _str);
            delete[] _str;
            _str = tmp;
            _capacity = n;
        }
    }
    void resize(size_t n, char ch = '\0') {
        if (n <= _size) {
            //删除数据--保留前n个
            _size = n;
            _str[_size] = '\0';
        }
        else {
            if (n > _capacity) {
                reserve(n);
            }
            size_t i = _size;
            while (i < n) {
                _str[i] = ch;
                ++i;
            }
            _size = n;
            _str[_size] = '\0';
        }
    }
    void push_back(char ch) {
        /*if (_size + 1 > _capacity) {
            reserve(_capacity * 2);
        }
        _str[_size] = ch;
        ++_size;
        _str[_size] = '\0';*/
        insert(_size, ch);
    }
    void append(const char* str) {
        //size_t len = strlen(str);
        //if (_size + len > _capacity) {
        //    reserve(_size + len);
        //}
        //strcpy(_str + _size, str);
        strcat(_str,str);
        //_size += len;
        insert(_size, str);
    }
    string& operator+=(char ch) {
        push_back(ch);
        return *this;
    }
    string& operator+=(const char* str) {
        append(str);
        return *this;
    }
    string& insert(size_t pos, char ch) {
        assert(pos <= _size);
        if (_size + 1 > _capacity) {
            reserve(2 * _capacity);
        }
        //int end = _size;
        //while (end >= (int)pos) {//有符号跟无符号类型比较会发生整型提升变成无符号类型
        //    _str[end + 1] = _str[end];
        //    --end;
        //}
        size_t end = _size+1;
        while (end > pos) {
            _str[end] = _str[end-1];
            --end;
        }
        _str[pos] = ch;
        ++_size;
        return *this;
    }
    string& insert(size_t pos, const char* str) {
        assert(pos <= _size);
        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;
        }
        /*size_t end = _size;
        for (size_t i = 0; i < _size + 1; ++i) {
            _str[end] = _str[end - len];
            --end;
        }*/
        //拷贝插入
        strncpy(_str + pos, str, len);
        _size += len;
        return *this;
    }
    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;
    }
    //swap(s1,s2);
    //s1.swap(s2);比上面更高效
    void swap(string& s) {
        std::swap(_str, s._str);
        std::swap(_size, s._size);
        std::swap(_capacity, s._capacity);
    }
    size_t find(char ch,size_t pos=0) {
        assert(pos < _size);
        for (size_t i = pos; i < _size; ++i) {
            if (_str[i] == ch) {
                return i;
            }
        }
        return npos;
    }
    size_t find(const char* str, size_t pos = 0) {
        assert(pos < _size);
        char* p = strstr(_str + pos, str);
        if (p == nullptr) {
            return npos;
        }
        else {
            return p - str;
        }
    }
    void clear() {
        _str[0] = '\0';
        _size = 0;
    }
private:
    char* _str;
    size_t _size;
    size_t _capacity;

    //static const size_t npos;
    static const size_t npos = -1;

    //static const double npos = -1.0;//错误,只针对整型
};

//const size_t string::npos = -1;

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

构造函数

//构造函数
    /*string() 
        :_str(new char[1])
        ,_size(0)
        ,_capacity(0)
    {
        _str[0] = '\0';
    }*/
    //string(const char* str=nulltr)不可以,strlen检测不到'\0'会崩
    //string(const char* str='\0')不可以,类型不匹配
    //string(const char* str="\0")可以,但是C语言规定常量字符串后面会有默认'\0'会造成歧义
    string(const char* str = "")
        :_size(strlen(str))//不包括'\0'的大小
    {
        _capacity = _size==0 ? 3 : _size;
        _str = new char[_capacity + 1];
        strcpy(_str, str);
    }

构造函数我们可以用无参和带参的构造,但是最好的方式是全缺省,const char* str = “” 是构造函数的默认参数。

拷贝构造

浅拷贝:拷贝出来的目标对象的指针和源对象的指针指向的内存空间是同一块空间。其中一个对象的改动会对另一个对象造成影响。
深拷贝:深拷贝是指源对象与拷贝对象互相独立。其中任何一个对象的改动不会对另外一个对象造成影响。

因为我们并不希望源对象与拷贝对象存在关系,所以我们需要实例化出新的对象再进行拷贝。

传统写法:

 string(const string& s)
        :_size(s._size)
        ,_capacity(s._capacity)
    {
        _str = new char[s._capacity+1];
        strcpy(_str, s._str);
    }

现代写法:

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

string(const string& s)

:_str(nullptr)

, _size(0)

, _capacity(0)

{

string tmp(s._str);

swap(tmp);

}

swap 函数的实现会交换当前对象和临时对象的内存空间资源,而临时对象会在析构时释放资源。

这种实现方式通过避免了不必要的内存拷贝,从而提高了拷贝构造函数的性能。

赋值运算符重载

传统写法:

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

            char* tmp = new char[s._capacity + 1];
            strcpy(tmp, s._str);
            delete[] _str;
            _str = tmp;

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

现代写法:

//现代写法2
string& operator=(const string& s)
{
    if (this != &s) //防止自己给自己赋值
    {
        string tmp(s); //用s拷贝构造出对象tmp
        swap(tmp); //交换这两个对象
    }
    return *this; //返回左值(支持连续赋值)
}

析构函数

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

扩容

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

获取对应位置字符

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

改变字符串大小


void resize(size_t n, char ch = '\0') {
    if (n <= _size) {
        //删除数据--保留前n个
        _size = n;
        _str[_size] = '\0';
    }
    else {
        if (n > _capacity) {
            reserve(n);
        }
        size_t i = _size;
        while (i < n) {
            _str[i] = ch;
            ++i;
        }
        _size = n;
        _str[_size] = '\0';
    }
}

迭代器

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

数字转字符串


string to_string(int value)
    {
        bool flag = true;
        if (value < 0)
        {
            flag = false;
            value = 0 - value;
        }

        string str;
        while (value > 0)
        {
            int x = value % 10;
            value /= 10;

            str += ('0' + x);
        }

        if (flag == false)
        {
            str += '-';
        }

        std::reverse(str.begin(), str.end());
        return str;
    }

字符/字符串任意位置插入

string& insert(size_t pos, char ch) {
    assert(pos <= _size);
    if (_size + 1 > _capacity) {
        reserve(2 * _capacity);
    }
    //int end = _size;
    //while (end >= (int)pos) {//有符号跟无符号类型比较会发生整型提升变成无符号类型
    //    _str[end + 1] = _str[end];
    //    --end;
    //}
    size_t end = _size+1;
    while (end > pos) {
        _str[end] = _str[end-1];
        --end;
    }
    _str[pos] = ch;
    ++_size;
    return *this;
}
string& insert(size_t pos, const char* str) {
    assert(pos <= _size);
    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;
    }
    /*size_t end = _size;
    for (size_t i = 0; i < _size + 1; ++i) {
        _str[end] = _str[end - len];
        --end;
    }*/
    //拷贝插入
    strncpy(_str + pos, str, len);
    _size += len;
    return *this;

字符/字符串的追加

void push_back(char ch) {
    /*if (_size + 1 > _capacity) {
        reserve(_capacity * 2);
    }
    _str[_size] = ch;
    ++_size;
    _str[_size] = '\0';*/
    insert(_size, ch);
}
void append(const char* str) {
    //size_t len = strlen(str);
    //if (_size + len > _capacity) {
    //    reserve(_size + len);
    //}
    //strcpy(_str + _size, str);
    strcat(_str,str);
    //_size += len;
    insert(_size, str);
}
string& operator+=(char ch) {
    push_back(ch);
    return *this;
}
string& operator+=(const char* str) {
    append(str);
    return *this;
}
}

从任意位置删除n个字符


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;
}

查找字符/字符串

size_t find(char ch,size_t pos=0) {
    assert(pos < _size);
    for (size_t i = pos; i < _size; ++i) {
        if (_str[i] == ch) {
            return i;
        }
    }
    return npos;
}
size_t find(const char* str, size_t pos = 0) {
    assert(pos < _size);
    char* p = strstr(_str + pos, str);
    if (p == nullptr) {
        return npos;
    }
    else {
        return p - str;
    }
}

将字符串置空

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

获取字符串

const char* c_str() {
    return _str;
}

比较运算符重载

bool operator>(const string& s) const {
    return strcmp(_str, s._str) > 0;
}
bool operator==(const string& s) const {
    return strcmp(_str, s._str) == 0;
}
bool operator>=(const string& s) const {
    return *this > s || *this == s;
}
bool operator<(const string& s) const {
    //return strcmp(_str, s._str) < 0;
    return !(*this >= s);
}
bool operator<=(const string& s) const {
    //return *this < s || *this == s;
    return !(*this > s);
}

流提取和流插入运算符重载

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

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

P1090 [NOIP2004 提高组] 合并果子 / [USACO06NOV] Fence Repair G

本题为洛谷&#xff1a; 本题非常简单&#xff0c;只需从小到大排序&#xff0c;再取前两项加到sum里&#xff0c;再次排序就好了&#xff1a; #include<iostream> #include<algorithm> using namespace std; int n,a[10001],sum; int main(){cin>>n;for(in…

统计大写辅音字母

题目&#xff1a; 英文辅音字母是除A、E、I、O、U以外的字母。本题要求编写程序&#xff0c;统计给定字符串中大写辅音字母的个数。 输入格式&#xff1a; 输入在一行中给出一个不超过80个字符、并以回车结束的字符串。 输出格式&#xff1a; 输出在一行中给出字符串中大写…

restful请求风格的增删改查-----查询and添加

一、前提&#xff1a; 使用软件&#xff1a;eclipse 正确创建实体类&#xff0c;并创建set、get、tostring、有/无参构造方法 二、查询&#xff1a; 前端&#xff1a; <% page language"java" contentType"text/html;charsetUTF-8"pageEncoding&qu…

Git TortoiseGit 安装使用详细教程

前言 Git 是一个免费的开源分布式版本控制系统&#xff0c;是用来保存工程源代码历史状态的命令行工具&#xff0c;旨在处理从小型到非常大型的项目&#xff0c;速度快、效率高。《请查阅Git详细说明》。TortoiseGit 是 Git 的 Windows Shell 界面工具&#xff0c;基于 Tortoi…

Vue.js前端开发零基础教学(六)

学习目标 了解什么是路由&#xff0c;能够说出前端后端路由的原理 掌握多种路由的使用方法&#xff0c;能够实现路由的不同功能 掌握Vue Router的安装及基本使用方法 5.1 初始路由 提到路由&#xff08;Route),一般我们会联想到网络中常见的路由器&#xff08;Router),…

PSA Group EDI 需求分析

PSA集团&#xff08;以下简称PSA&#xff09;中文名为标致雪铁龙集团&#xff0c;是一家法国私营汽车制造公司&#xff0c;致力于为全球消费者提供独具特色的汽车体验和自由愉悦的出行方案&#xff0c;旗下拥有标致、雪铁龙、DS、欧宝、沃克斯豪尔五大汽车品牌。 汽车制造企业对…

Lesson4--栈和队列

【本节目标】 1.栈 2.队列 3.栈和队列面试题 1.栈 1.1栈的概念及结构 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。 进行数据插入和删除操作的一端 称为栈顶&#xff0c;另一端称为栈底。 栈中的数据元素遵守后进先出 LIFO &…

【做一名健康的CSDNer】

程序员由于工作性质&#xff0c;常常需要长时间面对电脑&#xff0c;这可能对身心健康带来挑战。以下是一些实用的建议&#xff0c;帮助程序员保持身心健康&#xff1a; 规律生活&#xff1a;建立健康的生活习惯&#xff0c;包括规律的作息时间和固定的饮食时间&#xff0c;保证…

【深度学习】写实转漫画——CycleGAN原理解析

1、前言 上一篇&#xff0c;我们讲解了按照指定文本标签生成对应图像的CGAN。本篇文章&#xff0c;我们讲CycleGAN。这个模型可以对图像风格进行转化&#xff0c;并且训练还是在非配对的训练集上面进行的&#xff0c;实用性挺大 原论文&#xff1a;Unpaired Image-to-Image T…

数学建模--非线性规划模型+MATLAB代码保姆式解析

目录 1.简单介绍 2.求解方法 3.适用赛题 4.典型例题及相关分析 &#xff08;1&#xff09;问题引入 &#xff08;2&#xff09;决策变量&约束条件 &#xff08;3&#xff09;确定目标函数 &#xff08;4&#xff09;建立数学模型 5.MATLAB代码祝逐字句讲解 1.简单…

C++进阶:搜索树

目录 1. 二叉搜索树1.1 二叉搜索树的结构1.2 二叉搜索树的接口及其优点与不足1.3 二叉搜索树自实现1.3.1 二叉树结点结构1.3.2 查找1.3.3 插入1.3.4 删除1.3.5 中序遍历 2. 二叉树进阶相关练习2.1 根据二叉树创建字符串2.2 二叉树的层序遍历I2.3 二叉树层序遍历II2.4 二叉树最近…

用Cmake编译程序时,链接到FFmpeg库

用Cmake编译程序时&#xff0c;链接到FFmpeg库 一、前言 可喜可贺&#xff0c;折腾了一晚上终于把这个勾八链接成功了&#xff0c;已经要吐了。看到下面控制台的输出&#xff0c;吾心甚慰呀&#x1f62d; [100%] Linking CXX executable rknn_yolov5_demo [100%] Built targe…