【c++】string类的使用

这篇具有很好参考价值的文章主要介绍了【c++】string类的使用。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

一、标准库中的string类

1、简单介绍string类

2、string类的常用接口注意事项

2.1、string类对象的常用构造

2.2、string类对象的容量操作

2.3、string类对象的访问及遍历操作

2.4、string类对象的修改操作

二、string类的模拟实现


一、标准库中的string类

1、简单介绍string类

        (1)string是表示字符串的字符串类;

        (2)string类的接口与常规容器的接口基本相同,在添加了一些专门用来操作string的常规操作;

        (3)string的底层实际是:basic_string模板类的别名,typedef basic_string<char,char_traits,allocator> string;

        (4)不能操作多字节或者变长字符的序列。

2、string类的常用接口注意事项

2.1、string类对象的常用构造

        标准库给出的string类对象常用的构造函数有很多,我们经常用到的主流构造方式有三种:用模板提供的默认构造函数构造空的string类对象、用常量字符串构造string类对象以及用现有的string类对象进行拷贝构造string类对象。

【c++】string类的使用,c++,开发语言

2.2、string类对象的容量操作

【c++】string类的使用,c++,开发语言

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

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

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

        (4)reserve(size_t res_arg=0):为string预留空间,不改变有效元素个数,当reserve的参数小于string的底层空间总大小时,reserve不会改变容量的大小。

2.3、string类对象的访问及遍历操作

        string类对象的访问方式有三种:下标访问、迭代器访问、范围for访问。这里主要讨论迭代器访问方式。

        迭代器是一个类,现阶段可以把迭代器当成一个指针来使用(实际上不一定是指针),迭代器是在类的里边定义的,即内部类,使用方式如:string::iterator。string类中与迭代器搭配使用的成员函数包括begin()、end()、rbegin()、rend()。

【c++】string类的使用,c++,开发语言

2.4、string类对象的修改操作

【c++】string类的使用,c++,开发语言

        string类提供了很多字符串修改接口,需要说的是:在string尾部追加自字符时,s.push_back(c)/s.append(1,c)/s+='c'三种实现方式几乎一样,一般情况下更多的选用+=操作,+=操作不仅可以连接单个字符,还可以连接字符串;对string操作时,如果能够大概预估到待存储字符串的长度,可以先通过reserve把空间预留好。文章来源地址https://www.toymoban.com/news/detail-791186.html

二、string类的模拟实现

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

namespace lbj
{
    class string
    {
        friend ostream& operator<<(ostream& _cout, const string& s);
        friend istream& operator>>(istream& _cin, string& s);
        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);
            this->swap(tmp);
        }
        string& operator=(const string& s)
        {
            if (this != &s)
            {
                string temp(s);
                this->swap(temp);
            }
            return *this;
        }
        ~string()
        {
            if (_str)
            {
                delete[] _str;
                _str = nullptr;
            }
        }

        //

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


        /

        // modify
        void push_back(char c)
        {
            if (_size == _capacity)
                reserve(_capacity * 2);
            _str[_size++] = c;
            _str[_size] = '\0';
        }
        string& operator+=(char c)
        {   
            push_back(c);
            return *this;
        }
        void append(const char* str)
        {
            int len = strlen(str);
            if (_size + len > _capacity)
            {
                reserve(_size + len);
                //_capacity = _size + len;
            }
            strcpy(_str + _size, str);   //strcpy()会将‘\0’也拷贝过来,所以不需要手动添加'\0'
            _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 newSize, char c = '\0')
        {
            if (newSize > _size)
            {
                // 如果newSize大于底层空间大小,则需要重新开辟空间
                if (newSize > _capacity)
                {
                    reserve(newSize);
                }
                memset(_str + _size, c, newSize - _size);
            }
            _size = newSize;
            _str[newSize] = '\0';
        }

        void reserve(size_t newCapacity)
        {
            // 如果新容量大于旧容量,则开辟空间
            if (newCapacity > _capacity)
            {
                char* str = new char[newCapacity + 1];
                strcpy(str, _str);
                // 释放原来旧空间,然后使用新空间
                delete[] _str;
                _str = str;
                _capacity = newCapacity;
            }
        }



        /

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



        /

        //relational operators
        bool operator<(const string& s)const
        {
            int res = strcmp(_str, s._str);
            if (res < 0)
                return true;
            return false;
        }

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

        bool operator>(const string& s)const
        {
            int res = strcmp(_str, s._str);
            if (res > 0)
                return true;
            return false;
        }

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

        bool operator==(const string& s)const
        {
            int res = strcmp(_str, s._str);
            if (res == 0)
                return true;
            return false;
        }

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



        // 返回c在string中第一次出现的位置
        size_t find(char c, size_t pos = 0) const
        {
            for (size_t i = pos; i < _size; ++i)
            {
                if (_str[i] == c)
                    return i;//找到,返回下标
            }
            return -1;//未找到
        }

        // 返回子串s在string中第一次出现的位置
        size_t find(const char* s, size_t pos = 0) const
        {
            assert(s);
            assert(pos < _size);
            const char* src = _str + pos;
            while (*src)
            {
                const char* match = s;//如果不匹配,返回子串起始处重新查找
                const char* cur = src;
                while (*match && *match == *cur)//结束条件
                {
                    ++match;
                    ++cur;
                }
                if (*match == '\0')//找到子串
                {
                    return src - _str;//返回下标
                }
                else
                {
                    ++src;
                }
            }
            return -1;//未找到
        }

        // 在pos位置上插入字符c/字符串str,并返回该字符的位置
        string& insert(size_t pos, char c)
        {
            assert(pos <= _size);
            if (_size > _capacity)
            {
                //扩容
                char* newstr = new char[_capacity * 2 + 1];//开空间
                strcpy(newstr, _str);
                delete[] _str;
                _str = newstr;
                _capacity *= 2;
                //Expand(_capacity * 2);
            }

            //移数据
            for (int i = _size; i >= (int)pos; --i)
            {
                _str[i + 1] = _str[i];
            }
            _str[pos] = c;
            _size++;
            return *this;
        }

        string& insert(size_t pos, const char* str)
        {
            size_t len = strlen(str);
            if (_size + len > _capacity)//扩容
            {
                //扩容
                char* newstr = new char[_capacity * 2 + 1];//开空间
                strcpy(newstr, _str);
                delete[] _str;
                _str = newstr;
                _capacity *= 2;
                //Expand(_size + len);
            }

            //后移数据
            for (int i = _size; i >= (int)pos; --i)
            {
                _str[len + i] = _str[i];
            }

            //拷贝字符串
            while (*str != '\0')
            {
                _str[pos++] = *str++;
            }
            _size += len;
            return *this;
        }

        // 删除pos位置上的元素,并返回该元素的下一个位置
        string& erase(size_t pos, size_t len)
        {
            assert(pos < _size);
            if (pos + len >= _size)//pos位置之后全为0
            {
                _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;
    };

    //输入流重载
    istream& operator>>(istream& _cin, string& s)
    {
        //预分配100个空间
        char* str = (char*)malloc(sizeof(char) * 100);
        char* buf = str;
        int i = 1;
        //预处理:跳过流里面的所有空格和回车
        while ((*buf = getchar()) == ' ' || (*buf == '\n'));
        for (; ; ++i)
        {
            if (*buf == '\n') //回车跳出
            {
                *buf = '\0';
                break;
            }
            else if (*buf == ' ') //空格跳出
            {
                *buf = '\0';
                break;
            }
            else if (i % 100 == 0) //空间不足
            {
                i += 100; //追加100个空间
                str = (char*)realloc(str, i);
            }
            else  //每次getchar()一个值
            {
                buf = (str + i);//为了避免realloc返回首地址改变,不使用++buf,而是用str加上偏移.
                //每次读取一个字符
                *buf = getchar();
            }
        }
        //输入完成,更新s
        s._str = str;
        s._capacity = s._size = i;
        return _cin;
    }

    //输出流重载
    ostream& operator<<(ostream& _cout, const string& s)
    {
        for (size_t i = 0; i < s.size(); ++i)
        {
            _cout << s[i];
        }
        return _cout;
    }
};

到了这里,关于【c++】string类的使用的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【C++】string类的基础操作

    💗个人主页💗 ⭐个人专栏——C++学习⭐ 💫点击关注🤩一起学习C语言💯💫 目录 导读 1. 基本概述 2. string类对象的常见构造 3. string类对象的容量操作 4. string类对象的访问及遍历操作 5. 迭代器 6. string类对象的修改操作 6.1 基本修改操作 6.2 c_str()函数 6.3 find + npos、rfind和

    2024年03月11日
    浏览(43)
  • 【C++】string类的模拟实现

    前言:在上一篇中我们讲到了string类的使用方法,今天我们将进一步的去学习string类,去底层看看它顺带模拟实现部分的内容。 💖 博主CSDN主页:卫卫卫的个人主页 💞 👉 专栏分类:高质量C++学习 👈 💯代码仓库:卫卫周大胖的学习日记💫 💪关注博主和博主一起学习!一起努

    2024年03月21日
    浏览(43)
  • 【C++】string类的深入介绍

    作者:爱写代码的刚子 时间:2023.5.26 本篇博客主要深入介绍string类、string类的常用接口及操作,string中迭代器的使用,以及string中的部分方法。(由于篇幅有限,剩余方法以及string的深浅拷贝将在之后的博客介绍) 前言:C语言中,字符串是以’\\0’结尾的一些字符的集合,

    2024年02月08日
    浏览(34)
  • C++中string类的常用函数

    引言:在C语言中对于字符串的一些操作,例如在字符串末尾增加字符,对字符串拷贝等,我们可以通过调用库中函数来完成这些操作,在C++中,我们把这些常规操作封装成了string类,可以通过类对象直接调用这些函数,使得更加符合了面向对象的思想。 作用:返回字符串的有效字符长度

    2024年02月08日
    浏览(40)
  • 【C++】string类的深浅拷贝问题

    我们知道,定义一个类的时候,如果我们没有写构造,拷贝构造,赋值运算符重载,析构方法的话,编译器会自动生成。当该类成员中涉及到资源的管理时,实现的就是浅拷贝。所以,以上这几种方式是必须要程序猿手动实现的。 举例来看: 图中所示:实现了构造和析构,

    2023年04月26日
    浏览(40)
  • C++ 之 string类的模拟实现

    这学习我有三不学 昨天不学,因为昨天是个过去 明天不学,因为明天还是个未知数 今天不学,因为我们要活在当下,我就是玩嘿嘿~ –❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀-正文开始-❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–

    2024年04月27日
    浏览(31)
  • 【C++初阶】string 类的认识与学习

      在学习string类之前,先在这里推荐2个好用的网站,可以用来查阅C++的相关知识 https://cplusplus.com https://en.cppreference.com/w/ 上面的是非官方的,下面的官方的,但是个人感觉还是上面的好用。 简单来说, string 是C++中用来管理字符串的类。 他有很多接口,大致分为: 1.string类

    2024年02月09日
    浏览(47)
  • 【C++】——string类的介绍及模拟实现

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

    2024年02月07日
    浏览(54)
  • 【C++初阶】9. string类的模拟实现

    string类的完整实现放这里啦!快来看看吧 string类的作用就是将字符串类型实现更多功能,运算符重载,增删改查等等操作,所以其成员就包含char*的字符串 在之前的学习过程中,我们了解到类中存在的六个默认函数,其中就包含默认构造函数,那么对于string类是否需要用户自

    2024年02月09日
    浏览(34)
  • 【C++初阶】学习string类的模拟实现

    前面已经学习了string类的用法,这篇文章将更深入的学习string类,了解string类的底层是怎么实现的。当然,这里只是模拟一些常用的,不常用的可以看文档学习。 我们一共创建两个文件,一个是test.cpp文件,用于测试;另一个是string.h文件,用于声明和定义要模拟的string类。

    2024年02月03日
    浏览(52)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包