string类(二)

简介: string类

string类对象的修改操作

函数名 功能
push_back 在字符串末尾插入字符c
append 在字符串后追加一个字符串
operator+= 在字符串后追加字符串
c_str 返回C字符串
find+npos 从字符串pos位置开始往后找字符c,返回该字符在字符串中的位置
rfind 从字符串pos位置开始往前找字符c,返回该字符在字符串中的位置
substr 在字符串pos位置开始,截取n个字符,然后将其返回



在上面学习扩容原理以及介绍push_back这里不加赘述


append

6fa52a9c5625617d5711a9328ea655d3_662d786e378b4c899056a58de1f5c5f0.png

功能简单来说就是在字符串后面追加字符或者字符串


实现如下


void test()
{
  string s1("hello crush");
  string s2("!!!");
  //在字符串s1后面追加字符串s2
  s1.append(s2);
  cout << s1 << endl;
}


37a83f6debac88911d04b147e47bf82a_fc7fca7dbeaa4c2980c45e2013706b15.png


其实对于 append函数的使用很少,一般使用 operator+=,两者在功能上相似,并且后者相对简单且容易理解


替换上面的代码


void test()
{
  string s1("hello crush");
  string s2("!!!");
  //在字符串s1后面追加字符串s2
  s1 += s2;
  cout << s1 << endl;
}


29b3697c7035d9f85c3a392cc717c409_3fe7490a04aa41349dc00c64314f2804.png


区分assign和replace


447152b958715e0154c14850c67f6430_1914bdf063b144acb48d77a3561ecf14.png

e855ab6bf68f9eb4ff7812e3eab53f66_56194e57f4ef4ae88f7ed1cb56c1ce03.png


assign的功能是先将原有的字符串清空在进行替换;replace的功能是在原有字符串的基础上在某个位置计算一定的长度进行替换


实例如下


void test()
{
  string s1("hello world hello world");
  string s2("hello world hello world");
  s1.assign("hello crush", 5);
  cout << s1 << endl;
  s2.replace(6, 5, "crush");
  cout << s2 << endl;
}


86e306de74cd6c02ca89a44c37f74c80_db570af500dd4c97b02a9aaf1d06f3db.png


find

a01709cdb949834c077284774ea01649_aa3f20d865f44516a37bdfd7c824f533.png

功能简单来说就是,默认从第一个位置开始向后找某个字符,找到之后返回该字符所在的位置;若没有找到,则返回npos


示例如下


void test()
{
  string s("hello crush hello crush");
  cout << s << endl;
  //将' '替换成20%
  size_t pos = s.find(' ');
  while (pos != string::npos)
  {
  s.replace(pos, 1, "20%");
  pos = s.find(' ',pos+3);
  }
  cout << s << endl;
}


c_str

89848080e1bd044d0338be112c84577d_3af15022220042938b648767125cfe02.png

功能:将字符串转换成C格式字符串并返回


读取文件


void test()
{
  string file("test.cpp");
  //将string格式的字符串转换成C格式的字符串,以便进行读取
  FILE* fout = fopen(file.c_str(), "r");
  assert(fout);
  char ch = fgetc(fout);
  while (ch != EOF)
  {
  cout << ch;
  ch = fgetc(fout);
  }
  fclose(fout);
}


string类非成员函数

函数名 功能
operator+
operator>> 输入运算符重载
operator<< 输出运算符重载
getline 获取一行字符串
relational operators 大小比较


string类的模拟实现


传统写法


namespace myj
{
  class string
  {
  friend ostream& operator<<(ostream& out,string& s);
  friend istream& operator>>(istream& in, string& s);
  public:
  typedef char* iterator;//迭代器
  iterator begin()
  {
    return _str;
  }
  iterator end()
  {
    return _str + _size;
  }
        //构造函数
  string(const char* str = "")
  {
    _size = strlen(str);
    _capacity = _size;
    _str = new char[_capacity + 1];
    strcpy(_str, str);
  }
  //s2(s1)   拷贝构造
  string(const string& s)
  {
    _str = new char[s._capacity + 1];
    _capacity = s._capacity;
    _size = s._size;
    strcpy(_str, s._str);
  }
  //s1=s3  赋值重载
  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()
  {
    delete[] _str;
    _str = nullptr;
    _size = _capacity = 0;
  }
        //转换成C格式字符串,便于自定义类型的输出
  const char* c_str()
  {
    return _str;
  }
        //string的长度
  size_t size()
  {
    return _size;
  }
        //string的容量
  size_t capacity()
  {
    return _capacity;
  }
        //重载[]
  char& operator[](size_t pos)
  {
    assert(pos < _size);
    return _str[pos];
  }
        //预留空间
  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>_capacity,将会进行扩容
    reserve(n);
    for (size_t i = _size; i < n; i++)
    {
      _str[i] = ch;
    }
    _size = n;
    _str[_size] = '\0';
    }
    else
    {
    _str[n] = '\0';
    _size = n;
    }
  }
        //尾插
  void push_back(char ch)
  {
    if (_size == _capacity)
    {
    size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2;
    reserve(newcapacity);
    }
    _str[_size] = ch;
    _size++;
    _str[_size] = '\0';
  }
        //追加字符串
  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;
  }
        //字符插入
  string& insert(size_t pos, char ch)
  {
    assert(pos <= _size);
    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] = ch;
    _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;
  }
        //消除字符
  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);
    }
    return *this;
  }
        //查找字符
  size_t find(char ch, size_t pos = 0)
  {
    assert(pos < _size);
    while (pos < _size)
    {
    if (_str[pos] = ch)
    {
      return pos;
    }
    pos++;
    }
    return npos;
  }
        //查找字符串
  size_t find(const char* str, size_t pos = 0)
  {
    assert(pos < _size);
    const char* ptr = strstr(_str + pos, str);
    if (ptr == nullptr)
    {
    return npos;
    }
    else
    {
    return ptr - _str;
    }
  }
        //清楚string内容
  void clear()
  {
    _size = 0;
    _str[0] = '\0';
  }
  private:
  char* _str;
  size_t _size;
  size_t _capacity;
  const static size_t npos = -1;
  };
    //流提取
  ostream& operator<<(ostream& out,string& s)
  {
  for (size_t i = 0; i < s.size(); i++)
  {
    out << s[i];
  }
  return out;
  }
    //流插入
  istream& operator>>(istream& in, 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;
  }
}


现代写法


主要是对拷贝构造和赋值重载进行改进,并不是为了提高效率,而是方便理解


拷贝构造


void swap(string& s)
  {
    std::swap(_str, s._str);
    std::swap(_size, s._size);
    std::swap(_capacity, s._capacity);
  }
//s1(s2)
string(const string& s)
    :_str(nullptr)
    ,_size(0)
    ,_capacity(0)
  {
    string tmp(s._str);
    swap(tmp);
  }


思路:

将s2进行初始化;

创建临时变量string tmp拷贝构造s1;

交换tmp和s1的内容;


52332ebd201f6af061dbb6c99204b5db_e1041507ce0147b592259c3324b0da15.png


区分两个函数


string成员函数
swap(s1,s2);


62ddb923ab6c17f7e182945d7b5a5da3_1e72da20a4ea4cdba163555e35fb2711.png


进行三次深拷贝,交换s1和s2整体


s1.swap(s2);


a2c9de6756a3fda85e03f72aa7272bdd_a705f250d78244869706a67c10746cea.png


只改变s1和s2中指针指向的内容


赋值重载

这里便可以利用上面**s1.swap(s2);**的思想


//s1=s2
string& operator=(const string& s)
  {
    if (this != &s)
    {
    string tmp(s);
    swap(tmp);
    }
    return *this;
  }

f85a96dd3a7bcee415489b41f35cf1db_4184400587f4413eb67cea245a791ee2.png


目录
相关文章
|
1月前
|
索引 Python
模拟实现一个简单的string类
这个示例中,定义了一个简单的 `MyString`类,包含了常用的字符串操作,比如初始化、字符串拼接、长度获取、索引访问、大小写转换、相等判断等功能。请根据需求进行适当的修改和扩展。 买CN2云服务器,免备案服务器,高防服务器,就选蓝易云。百度搜索:蓝易云
22 5
|
2月前
|
存储 C++ 容器
C++入门指南:string类文档详细解析(非常经典,建议收藏)
C++入门指南:string类文档详细解析(非常经典,建议收藏)
44 0
|
5天前
|
C语言 C++
【C++】string类(常用接口)
【C++】string类(常用接口)
13 1
|
2天前
|
编译器 C++
【C++】继续学习 string类 吧
首先不得不说的是由于历史原因,string的接口多达130多个,简直冗杂… 所以学习过程中,我们只需要选取常用的,好用的来进行使用即可(有种垃圾堆里翻美食的感觉)
7 1
|
2天前
|
算法 安全 程序员
【C++】STL学习之旅——初识STL,认识string类
现在我正式开始学习STL,这让我期待好久了,一想到不用手撕链表,手搓堆栈,心里非常爽
9 0
|
2天前
|
存储 安全 测试技术
【C++】string学习 — 手搓string类项目
C++ 的 string 类是 C++ 标准库中提供的一个用于处理字符串的类。它在 C++ 的历史中扮演了重要的角色,为字符串处理提供了更加方便、高效的方法。
10 0
【C++】string学习 — 手搓string类项目
|
5天前
|
C++
【C++】string类(介绍、常用接口)
【C++】string类(介绍、常用接口)
16 2
|
18天前
|
存储 网络协议 Java
Java String类
Java String类
11 0
|
22天前
|
存储 安全 C语言
【C++】string类
【C++】string类
|
23天前
|
存储 Java 编译器
Java String 类
4月更文挑战第14天