C++利剑string类(详解)

前言:大家都知道在C语言里面的有  char  类型,我接下来要讲的 string 类功能是使用 char  类型写的类,当然这个是C++官方写的,接下来我们将会学会使用它,我们会发现原来  char  这种类型是还能这么好用,授人以鱼不如授人以渔,接下来我将会讲不少干货,不仅仅是教会我们使用,还会教我们如何模拟实现一个  string  类,我也会教大家如何去读英文文档,话不多说,正文开始。

一,string  类初识

1)英文文档的查找和阅读

想要了解一个语言里面的一个语法,有什么比直接去它的官网看原汁原味的英文文档更加得劲呢?我现在贴出C++的官网cplusplus.com/reference/

打开之后我们会看到这个页面

因为新版本不具有搜索功能,为了我们方便使用,我们切回老版本,点击图上的这个

之后我们就能在上面的reserch进行搜索了

我们搜索  string  就会显示 string 类的提供的所有接口和功能,我们先看它对string类的描述,也就是第一大段

这上面明确说明了,string类是一串char字符,并且提供了一系列的接口,在下面是它的接口或者成员函数,让我们来看看,如何查看成员函数的功能,使用方法。

我们阅读英文文献不一定要全部明白意思,我们可以从上面的四个方面入手,就能大概理解功能和使用方法,碰到不会的单词我们可以用搜索引擎,但不建议使用翻译软件直接翻译,因为这样即不准确也不利用我们的成长,以后我们还会阅读不少的英文文献,只有自身硬才能笑到最后。

2)string类初步使用

string 如何创建对象

在使用时,我们首先可以把它定义的对象当作一个字符串,但是这个对象拥有很多C语言字符串没有的特性,比如不需要我们考虑它的空间够不够,我们可以使用运算符对它进行操作,也就是进行+,+=,=等操作,并且提供了许多接口帮助我们减少手搓的代码量

话不多说,我们先定义一个string 对象吧

string c1;      //里面只有一个\0
string c2("wzdhxhn");   //里面是"wzdxhn\0"
string c3=("wzdxhn");   //里面是"wzdxhn\0"
string c4=c3;           //里面也是"wzdxhn\0"
string c5(c4);          //里面还是"wzdxhn\0"
c1=c5+c4;              //里面可是"wzdxhnwzdxhn\0"哦
c5+=c5;                  //里面是"wzdxhnwzdxhn\0"哦
for(int i=0;i<7;i++)
c2[i]=6;                  //c2里面的内容将会全部变成6
cout<<c1;
cin>>c1;                    //支持输入输出流

没错,真的是一场酣畅淋漓的初始化和赋值,string都支持这种操作,并且拷贝都是深拷贝哦,如果在C里面我们就需要循坏进行赋值了,刚开始是不是就感受到了它的便利。编译器:最终还是我承受了一切。

string  成员函数的使用

前提知识:size_t npos = -1这个是C++库里面的,代表整形的最大值,如果它是默认参数,代表知道\0等结束标志结尾

1)size()

sizeicon-default.png?t=N7T8https://legacy.cplusplus.com/reference/string/string/size/

 没有函数参数,这个函数可以获取string里面字符串的长度,不包括\0,然后返回

string s("hello");
cout<<s.size();      //输出s的长度5
2)  length() 

string::length - C++ Referenceicon-default.png?t=N7T8https://legacy.cplusplus.com/reference/string/string/length/

 功能类似size,没有参数,也是返回字符串长度,不包括\0

string s("hello");
cout<<s.length();      //输出s的长度5
3)  max_size() 

 
string::max_size - C++ Referenceicon-default.png?t=N7T8https://legacy.cplusplus.com/reference/string/string/max_size/

 没有参数,返回字符串里面ASCLL码值的最大值这个可以改变字符串的大小,

4)resize()

string::resize - C++ Referenceicon-default.png?t=N7T8https://legacy.cplusplus.com/reference/string/string/resize/

 只有一个参数就是字符串调整后的大小(以\0为标注),没有返回值,可以扩大和缩小字符串长度,扩大可以指定一个参数填充,也可以选择不指定,这个参数有默认参数,但要注意这个如果指定大小小于字符串的大小则会将数据覆盖

string s("hello");
cout<<s.resize(10,'6');    //输出:hello66666
cout<<s.resize(2);         //输出:he
 5)  capacity()

string::capacity - C++ Referenceicon-default.png?t=N7T8https://legacy.cplusplus.com/reference/string/string/capacity/

没有参数,返回一个无符号整形,代表调整后储存字符串空间的大小,这个会返回string类的字符串空间的容量,要注意的是,字符串空间的容量不等于长度,可能有一些空间存在,但是我们没使用,相当于多开了空间

6)    reserve() 

string::reserve - C++ Referenceicon-default.png?t=N7T8https://legacy.cplusplus.com/reference/string/string/reserve/一个参数没有返回值,这个可以重新定义容量,但是要注意只能扩大,不能缩小容量,因为编译器会做判断,如果重定义的容量小于之前的字符串空间的容量就不会进行任何操作,也不会报错。只有一个参数,就是你再次定义的容量大小

7)  clear() 

string::clear - C++ Referenceicon-default.png?t=N7T8https://legacy.cplusplus.com/reference/string/string/clear/没有参数,没有返回值,顾名思义,清理数据,大小和长度。,但是不会改变开的空间大小,也就是字符串空间大小

8)    at() 

string::at - C++ Referenceicon-default.png?t=N7T8https://legacy.cplusplus.com/reference/string/string/at/这个相当于下标访问,只有一个参数就是你要访问的字符串位置 ,最后返回你要的下标元素的引用

string s("hello");
s.at(2);    //等价于s[2]
9)  back() /front()

 string::back - C++ Referenceicon-default.png?t=N7T8https://legacy.cplusplus.com/reference/string/string/back/

 没有参数,返回最后一个字符,front()则是返回第一个字符

string s("hello");
cout<<s.back();       //输出:o
 10)append()

 string::append - C++ Referenceicon-default.png?t=N7T8https://legacy.cplusplus.com/reference/string/string/append/

 这个有两个函数参数,一个是插入的字符串或者字符,第二个参数有默认参数0,代表插入的位置,返回类型是插入后的string类

string s("hello");
s.append(" world");
cout<<s;      //输出:hello world
11)  push_back() 

string::push_back - C++ Referenceicon-default.png?t=N7T8https://legacy.cplusplus.com/reference/string/string/push_back/这个成员函数有一个参数,没有返回值,是要注意插入的只能是字符,或者ASCLL码值而且是尾插,插入字符串请使用append

string s("nihao");
s.push_back('h');  
cout<<s;         //输出:nihaoh
10)    insert() 

string::insert - C++ Referenceicon-default.png?t=N7T8https://legacy.cplusplus.com/reference/string/string/insert/

这个函数支持的参数很多

从图什么我们能知道,返回类型是插入后的string类或者迭代器,这个insert功能强大,不仅支持插入字符,也支持字符串,支持各种各样的插入方式,即带来了遍历也变得复杂了

13)erase

string::erase - C++ Referenceicon-default.png?t=N7T8https://legacy.cplusplus.com/reference/string/string/erase/

这个函数功能很明确了,就是删除字符串,没有参数,返回值是删除后的string类或者迭代器,因此不做举例了

14)c_str()

string::c_str - C++ Referenceicon-default.png?t=N7T8https://legacy.cplusplus.com/reference/string/string/c_str/这个会将string类型 转化为C语言的char* 类型,返回类型是  const char*   ,但要注意返回类型是const类型,只读不写

15)find()/rfind

string::find - C++ Referenceicon-default.png?t=N7T8https://legacy.cplusplus.com/reference/string/string/find/

这个函数的作用就是查找字符或者字符串里面的字符,返回它在字符串里面的位置,注意找字符串的时候不是找子字符串而是找属于这个子串里面的字符

 find()是从前往后找,rfind()则是从后往前找,参数差不多

string s("hello,world");
cout<<s.find('l',5);  结果是:10,返回为world里面的l,因为的从5 o开始查找的
16)substr()

string::substr - C++ Referenceicon-default.png?t=N7T8https://legacy.cplusplus.com/reference/string/string/substr/这个函数的作用就是返回原字符串中的一个子字符串,返回参数为char* ,参数很简单,应该是子字符串的位置,一个是长度,如果不指定长度,默认到\0

string s("hello world");
cout<<s.substr(0,5);  //输出:hello
17)getline()

getline (string) - C++ Referenceicon-default.png?t=N7T8https://legacy.cplusplus.com/reference/string/string/getline/这个函数的作用就是cin的一个拓展,没有参数和没有返回值,众所周知,cin输入字符串碰到空白会暂停,但是getline要碰到\0才会停止

string s;
cin>>s;     //输入:jascsahjas jscasjbsnc,但最后只有jascsahjas成功输出了
s.getline(); //输入:jascsahjas jscasjbsnc    s里面是:jascsahjas jscasjbsnc

二,模拟实现

备注:博主想偷懒了,答应大家的模拟实现不能再给大家做详细的解释了,但我会贴出源码供大家参考,里面只有一点点的注释,如果大家有不懂的,可以评论区@我,我会给大家一一解答,大家记得先看下面的私有成员,不要直接从头看到尾哦

namespace bit     //使用命名空间,防止于库的string类型冲突

{

  class string

  {

  public:

    typedef char* iterator;      //string类的迭代器可以使用这个代替

  public:

    string(const char* str = "") //当无参数时,默认只有一个\0

    {

      _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);

    string& operator+=(const char* str);

    void clear()    //清除数据,但空间不变,尽量减少开空间的频率

    {

      _size = 0;

      _str[_size] = '\0';

    }

    void swap(string& s)

    {

      std::swap(_str, s._str);  //官方库的swap函数,又是一个偷懒小技巧

      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); //调用C官方库,初始化,不懂,参考我以前的博客

      }

      _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  //要记住const类型要单独处理

    {

      assert(index < _size);

      return _str[index];

    }



    /

    //relational operators

    bool operator<(const string& s)const

    {

      int res = strcmp(_str, s._str); //C官方库,以前博客有这种函数的模拟实现和讲解

      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   //只读不改,最好const,同时支持非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:

    friend ostream& operator<<(ostream& _cout, const bit::string& s);

    friend istream& operator>>(istream& _cin, bit::string& s);

  private:

    char* _str;

    size_t _capacity;

    size_t _size;

  };

};



//输入流重载

istream& bit::operator>>(istream& _cin, bit::string& s)

{

  //预分配100个空间

  char *str = (char *)malloc(sizeof(char)*100);

  char *buf = str;        //buf可以防止频繁开空间

  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& bit::operator<<(ostream& _cout, const bit::string& s)

{

for (size_t i = 0; i < s.size(); ++i)

{

_cout << s[i];

}

return _cout;

}

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

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

相关文章

Flutter学习(七)GetX offAllNamed使用的问题

背景 使用GetX开发应用的时候&#xff0c;也可能有人调用过offAllNamed&#xff0c;会发现所有controller的都被销毁了 环境 win10 getx 4.6.5 as 4 现象 从A页面&#xff0c;跳转到B页面&#xff0c;然后调用offAllNamed进行回到A页面&#xff0c;观察controller声明周期…

Python程序员入门指南:学习时间和方法

文章目录 标题Python程序员入门指南&#xff1a;学习时间、方法和就业前景学习方法建议学习时间 标题 Python程序员入门指南&#xff1a;学习时间、方法和就业前景 Python是一种流行的编程语言&#xff0c;它具有简洁、易读和灵活的特点。Python可以用于多种领域&#xff0c;如…

CentOS或RHEL安装code-server(vscode-web)

下载rpm安装包 网络下载或者下载到本地再上传到服务器&#xff0c;点击访问国内下载地址&#xff0c;不需要积分curl -fOL https://github.com/coder/code-server/releases/download/v4.19.1/code-server-4.19.1-amd64.rpm安装 rpm -i code-server-4.19.1-amd64.rpm关闭和禁用…

IP地理定位技术的服务内容详解

IP地理定位技术是一种通过IP地址确定设备或用户地理位置的技术&#xff0c;广泛应用于广告定向、网络安全、位置服务等领域。本文将深入探讨IP地理定位技术的服务内容&#xff0c;解析其在不同场景中提供的多种服务。 1. 准确的地理位置信息提供&#xff1a; IP地理定位技术的…

CGAL中2D三角剖分的数据结构

1、定义 三角剖分数据结构是一种设计用于处理二维三角剖分表示的数据结构。三角剖分数据结构的概念主要是设计用作CGAL2D三角剖分类的数据结构&#xff0c;这些类是嵌入平面中的三角剖分。然而&#xff0c;这个概念似乎更一般&#xff0c;可以用于任何可定向的无边界三角剖分曲…

6.1810: Operating System Engineering <Lab2 syscall: System calls>

课程链接&#xff1a;6.1810 / Fall 2023 一、本节任务 二、要点 操作系统要满足三要素&#xff1a;并发、隔离、交互&#xff08;multiplexing, isolation, and interaction&#xff09;。 宏内核&#xff08;monolithic kernel&#xff09;&#xff1a;是操作系统核心架构…

开源图床Qchan本地部署远程访问,轻松打造个人专属轻量级图床

文章目录 前言1. Qchan网站搭建1.1 Qchan下载和安装1.2 Qchan网页测试1.3 cpolar的安装和注册 2. 本地网页发布2.1 Cpolar云端设置2.2 Cpolar本地设置 3. 公网访问测试总结 前言 图床作为云存储的一项重要应用场景&#xff0c;在大量开发人员的努力下&#xff0c;已经开发出大…

基于机器深度学习的交通标志目标识别

在线工具推荐&#xff1a; 三维数字孪生场景工具 - GLTF/GLB在线编辑器 - Three.js AI自动纹理化开发 - YOLO 虚幻合成数据生成器 - 3D模型在线转换 - 3D模型预览图生成服务 智能交通系统&#xff08;ITS&#xff09;&#xff0c;包括无人驾驶车辆&#xff0c;尽管在道路…

最受好评的 5 款最佳安卓手机数据恢复工具

您想从 Android 手机中恢复永久删除或丢失的数据和文件吗&#xff1f;您可以借助顶级 Android 数据恢复软件来完成此操作。如果您的数据已被删除、损坏或格式化&#xff0c;则可以将已删除的文件恢复到您的 Android 手机中。Android 设备丢失文件的原因可能有多种。 不管你的手…

非全自研可视规则引擎RuleLinK可视化之路

导读 上一篇《非全自研可视化表达引擎-RuleLinK》介绍了RuleLink的V1.0版本&#xff0c;虽说一定程度上消除了一些配置相关的样板式代码&#xff0c;也肉眼可见的消除了一些研发资源的浪费&#xff1b;RuleLink的初衷是让业务配置变得简单&#xff0c;是面向运营同学。要真正面…

聚观早报 |国行PS5轻薄版开售;岚图汽车11月交付7006辆

【聚观365】12月2日消息 国行PS5轻薄版开售 岚图汽车11月交付7006辆 比亚迪推出12月限时优惠 特斯拉正式交付首批Cybertruck 昆仑万维发布「天工 SkyAgents」平台 国行PS5轻薄版开售 索尼最新的PlayStation5主机&#xff08;CFI-2000型号组-轻薄版&#xff09;国行版本正…

OpenHarmony 关闭息屏方式总结

前言 OpenHarmony源码版本&#xff1a;4.0release 开发板&#xff1a;DAYU / rk3568 一、通过修改系统源码实现不息屏 修改目录&#xff1a;base/powermgr/power_manager/services/native/profile/power_mode_config.xml 通过文件中的提示可以知道DisplayOffTime表示息屏的…

EasyExcel两行表头

例子&#xff1a; 代码&#xff1a; StorageService localStorageService storageFactory.getLocalStorageService();String path "";// 文件信息String dateTime DateUtils.formatTimestampToString(new Date());String title "xxx统计";String fil…

前端学习系列之CSS

目录 CSS 简介 发展史 优势 基本语法 引用方式 内部样式 行内样式 外部样式 选择器 id选择器 class选择器 标签选择器 子代选择器 后代选择器 相邻兄弟选择器 后续兄弟选择器 交集选择器 并集选择器 通配符选择器 伪类选择器 属性选择器 CSS基本属性 优…

七、ZooKeeper选举机制

目录 1、概念 2、全新集群选举 3、非全新集群选举 zookeeper默认的算法是FastLeaderElection,采用投票数大于半数则胜出

接口测试基础知识

一、接口测试简介 什么是接口测试&#xff1f; 接口测试是测试系统组件间接口的一种测试&#xff0c;主要用于检测外部系统与系统之间以及内部各个子系统之间的交互点。 测试的重点&#xff1a; 检查数据的交换&#xff0c;传递和控制管理过程&#xff1b;检查系统间的相互…

OpenTelemetry系列 - 第1篇 相关概念

目录 一、背景二、概念2.1 Traces & Span2.2 Metrics2.3 Logs2.4 Baggage2.5 OTel2.6 OTLP2.7 Resources2.8 Instrumentation Scope2.9 Sampling 三、核心组件 一、背景 OpenTelemetry是一个可观察性框架和工具包&#xff0c;旨在创建和管理遥测数据&#xff0c;如跟踪、指…

一个用c#瞎写的sftp工具

0.下载地址 https://wwus.lanzouj.com/iOZUv1gkgpze 密码:123456 1.能进行单个和批量下载, 没有弄上传 2.速度奇差,可能是某些地方没弄好.有一定的进度显示,但是不太准. 3.很多地方没弄好,有能力的自己弄一下 4.在app.config文件配置sftp

深度学习第4天:感知机模型

☁️主页 Nowl &#x1f525;专栏《机器学习实战》 《机器学习》 &#x1f4d1;君子坐而论道&#xff0c;少年起而行之 ​ 文章目录 感知机模型介绍 神经网络搭建感知机 结构 准备训练数据 感知机的损失函数与优化方法 测试结果 完整代码 多层感知机 结语 感知机模…

火车头插件-最全火车头伪原创图片存储等插件

火车头插件。作为一个功能强大的工具&#xff0c;火车头插件以其众多特色引起了广大用户的关注。而其中&#xff0c;火车头采集器更是备受瞩目。我们将分享火车头插件的安装教程&#xff0c;还会深入了解火车头伪原创插件的应用。 火车头插件安装教程 我们来安装火车头插件&a…