C++中String的语法及常用接口用法

简介: 在C语言中,string是一个标准库类(class),用于处理字符串,它提供了一种更高级、更便捷的字符串操作方式,string 类提供了一系列成员函数和重载运算符,以便于对字符串进行操作和处理。

在C语言中,string是一个标准库类(class),用于处理字符串,它提供了一种更高级、更便捷的字符串操作方式,string 类提供了一系列成员函数和重载运算符,以便于对字符串进行操作和处理。

一、string类

在学习 string 前,我们不妨先来了解一下 string 类到底是什么,有什么用呢?我们先来了解一下基本的概念吧

C++标准库都是英语解释。我们也应该试着去适应,不懂的可以查阅。当然,在这里我就直接给出翻译,主要是以下内容:

字符串是表示字符序列的类;

  • 标准的字符串类提供了对此类对象的支持,其接口类似于标准字符容器的接口,但添加了专门用于操作单字节字符字符串的设计特性。
  • string类是使用char(即作为它的字符类型,使用它的默认char_traits和分配器类型(关于模板的更多信息,请参阅basic_string)。
  • string类是basic_string模板类的一个实例,它使用char来实例化basic_string模板类,并用char_traits和allocator作为basic_string的默认参数(根于更多的模板信息请参考basic_string)。
  • 注意,这个类独立于所使用的编码来处理字节:如果用来处理多字节或变长字符(如UTF-8)的序列,这个类的所有成员(如长度或大小)以及它的迭代器,将仍然按照字节(而不是实际编码的字符)来操作。

二、string的常用见用法

2.1 string对象的构造

2.1.1 string对象的构造的使用方法

最为常用的无非就是我们用串string来构造一个对象,也就是存储一个字符,常用的方法有如下几点:

  • string()——构造空的 string 类对象,即空字符串;
  • string(const char* s)——用 char* 来构造 string 类对象;
  • string(size_t n, char c)——string类对象中包含n个字符c
  • string(const string&s)——拷贝构造函数

下面是使用方法所对应的实例,帮助更好的理解其用法。

三、string常用结构的底层实现

3.1 初建结构

我们通过上述的构造,不难发现也不难理解string的底层其实就是一个字符指针,该指针指向一个数组。当然,我们还需要两个变量来维护其有效长度(_size)数组容量(_capacity)

其次,我们自己实现的string类为了区分std命名空间,我们可自己设置一个命名空间。处型的模拟实现如下:

namespace gtm
{
  class string
  {
     public:
        //string()
    //  :_str(new char[1])
    //  , _size(0)
    //  ,_capacity(0)
    //{
    //}
    //string(const char* str)
    //  :_str(new char[strlen(str) + 1])  //三次strlen函数,效率低。
    //  ,_size(strlen(str))
    //  ,_capacity(strlen(str))
    //{
    //  strcpy(_str, str);
    //}
    // 不再使用strlen函数,初始化列表与变量声明顺序固定
    string(const char* str = "") //默认空串。注意:空串是以 \0 结尾
    {
      _size = strlen(str);
      _capacity = _size;
      _str = new char[_size + 1];
      strcpy(_str, str);
    }
        ~string()
    {
      delete[] _str;
      _str = nullptr;
      _size = _capacity = 0;
    }
     private:
    char* _str;
    size_t _size;
    size_t _capacity;
  };

3.2 返回大小和容量

这两个部分,是比较容易实现的两部分。同时也是较为常用的两部分。具体如下:

size_t size() const
    {
      return _size;
    }
    size_t capacity() const
    {
      return _capacity;
    }

3.3 拷贝构造和赋值重载

这两部分较为复杂的两部分。其中均需要深拷贝去实现完成,而浅拷贝是不可以的。注意:拷贝构造使用一个已定义变量去初始化另一个变量,赋值重载是两个已定义变量进行赋值

具体实现如下:

//深拷贝
    //string(const string& s)
    //  :_str(new char[s._capacity+1])
    //  ,_size(s._size)
    //  ,_capacity(s._capacity)
    //{
    //  strcpy(_str, s._str);
    //}
    void swap(string& tmp)
    {
      //调用全局的swap
      ::swap(_str, tmp._str);
      ::swap(_size, tmp._size);
      ::swap(_capacity, tmp._capacity);
    }
    //借助变量tmp
    string(const string& s)
      :_str(nullptr) 
      , _size(0)
      , _capacity(0)
    {
      string tmp(s._str);
      swap(tmp);
    }
    //赋值
    //string& operator=(const string& s)
    //{
    //  if(this == &s)
    //  {
    //    return *this;
    //  }
    //  //先开空间拷贝数据,以防new失败销毁原来的空间
    //  char* tmp = new char[s._capacity + 1];
    //  strcpy(tmp, s._str);
    //  delete[] _str;
    //  _str = tmp;
    //  _size = s._size;
    //  _capacity = s._capacity;
    //  return *this;
    //  //delete[] _str;
    //  //_str = new char[s._capacity + 1];
    //  //strcpy(_str, s._str);
    //  //_size = s._size;
    //  //_capacity = s._capacity;
    //  return *this;
    //}
    //string& operator=(const string& s)
    //{
    //  if(this == &s)
    //  {
    //    return *this;
    //  }
    //  string tmp(s._str);
    //  swap(tmp);
    //  return *this;
    //}
    string& operator=(string s)
    {
      if (this == &s)
      {
        return *this;
      }
      swap(s);
      return *this;
    }

上述的辅助重载我们巧妙地借助了临时变量s。当赋值完成后,出了作用域s会自动调用戏后进行销毁,这里是需要反复理解的。

3.4 扩容(reserve)

我们可简单的理解reserve为扩容(扩容的前提为要求的容量比原来的大),但是我们要记得把字符数组中原有的内容拷贝过来,并且释放之前所动态开辟的空间。 具体实现如下:

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

3.5 插入(push_back、append、operator+=、insert)

插入的实现,主要的点就是是否要进行扩容。其次,当我们实现push_back和append后,其他的均可复用这两个结构进行实现。具体实现如下:

void push_back(char ch)
    {
      if (_size == _capacity)
      {
        reserve(_capacity == 0 ? 4 : _capacity * 2);
      }
      _str[_size] = ch;
      _size++;
      _str[_size] = '\0';
    }
    void append(const char* str)
    {
      size_t len = strlen(str);
      if (len + _size > _capacity)
      {
        reserve(len + _size >= _capacity * 2 ? len + _size : _capacity * 2);
      }
      strcpy(_str + _size, str);
      _size += len;
    }
    void append(const string& s)
    {
      append(s._str);
    }
    void append(int n, char ch)
    {
      reserve(_size + n);
      for (int i = 0; i < n; i++)
      {
        push_back(ch);
      }
    }
    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 == _capacity)
      {
        reserve(_capacity == 0 ? 4 : _capacity * 2);
      }
      //注意,当运算数一个是有符号,另一个是无符号时,有符号的运算数会强制类型转换为无符号数。pos等于0的位置插入,end--后为超大数据,会出错。
      //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 (len + _size > _capacity)
      {
        reserve(len + _size >= _capacity * 2 ? len + _size : _capacity * 2);
      }
      size_t end = _size + len;
      while (end >= pos+len)
      {
        _str[end] = _str[end - len];
        end--;
      }
      for (int i = pos,j=0; j < len;j++, i++)
      {
        _str[i] = str[j];
      }
      _size += len;
      return *this;
    }

string 在C++中算是比较重要的了,也是入门时必须所学的容器。在平常中使用的频率较高,所以我们不仅要掌握其简单的用法,更应该去了解其底层的实现。这有助于我们后续的使用和理解。本篇文章列举出了string中常用的语法和接口底层的底层实现,这些都是我们应该熟练掌握的内容。

相关文章
|
6天前
|
存储 安全 编译器
第二问:C++中const用法详解
`const` 是 C++ 中用于定义常量的关键字,主要作用是防止值被修改。它可以修饰变量、指针、函数参数、返回值、类成员等,确保数据的不可变性。`const` 的常见用法包括:
38 0
|
28天前
|
存储 C++ 容器
【C++】map、set基本用法
本文介绍了C++ STL中的`map`和`set`两种关联容器。`map`用于存储键值对,每个键唯一;而`set`存储唯一元素,不包含值。两者均基于红黑树实现,支持高效的查找、插入和删除操作。文中详细列举了它们的构造方法、迭代器、容量检查、元素修改等常用接口,并简要对比了`map`与`set`的主要差异。此外,还介绍了允许重复元素的`multiset`和`multimap`。
30 3
【C++】map、set基本用法
|
26天前
|
C语言 C++ 容器
【c++丨STL】string模拟实现(附源码)
本文详细介绍了如何模拟实现C++ STL中的`string`类,包括其构造函数、拷贝构造、赋值重载、析构函数等基本功能,以及字符串的插入、删除、查找、比较等操作。文章还展示了如何实现输入输出流操作符,使自定义的`string`类能够方便地与`cin`和`cout`配合使用。通过这些实现,读者不仅能加深对`string`类的理解,还能提升对C++编程技巧的掌握。
55 5
|
26天前
|
存储 编译器 C语言
【c++丨STL】string类的使用
本文介绍了C++中`string`类的基本概念及其主要接口。`string`类在C++标准库中扮演着重要角色,它提供了比C语言中字符串处理函数更丰富、安全和便捷的功能。文章详细讲解了`string`类的构造函数、赋值运算符、容量管理接口、元素访问及遍历方法、字符串修改操作、字符串运算接口、常量成员和非成员函数等内容。通过实例演示了如何使用这些接口进行字符串的创建、修改、查找和比较等操作,帮助读者更好地理解和掌握`string`类的应用。
42 2
|
6天前
|
C++
第十三问:C++中静态变量的用法有哪些?
本文介绍了 C++ 中静态变量和函数的用法及原理。静态变量包括函数内的静态局部变量和类中的静态成员变量,前者在函数调用间保持值,后者属于类而非对象。静态函数不能访问非静态成员,但可以通过类名直接调用。静态链接使变量或函数仅在定义文件内可见,避免命名冲突。
18 0
|
2月前
|
C++ 容器
|
2月前
|
存储 安全 C++
【C++打怪之路Lv8】-- string类
【C++打怪之路Lv8】-- string类
26 1
|
2月前
|
C++ 容器
|
2月前
|
C++ 容器
|
2月前
|
存储 C++ 容器