string的使用和模拟实现-1

简介: string的使用和模拟实现

string的介绍

string是一个类,可以看成是一个用模板写的顺序表,它的底层结构和顺序表基本是一样的,一个字符指针和一个表示存储数据的个数的size,还有一个表示容量大小的capacity,我们知道C++需要兼容C语言,所以它的字符串后面也是需要有一个‘\0’,的但是size和capacity的大小是不包含这个‘\0’的,因此实际的容量要比capacity大一个。


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


总结:


  1. string是表示字符串的字符串类。
  2. 该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作。
  3. string在底层实际是:basic_string模板类的别名,typedef basic_string<char, char_traits, allocator> string;
  4. 不能操作多字节或者变长字符的序列。


结构

string的结构和顺序表很相似,一个存放字符的指针,还有一个标记个数的size,还有一个标记容量的capacity。

class
{
  private:
      char* _str;
      size_t _size;
      size_t _capacity;
}


string的常用接口


构造和析构

构造函数我们可以用个缺省参数,直接搞定无参和有参的情况,然后使用初始化列表把size和capacity给初始化一下,然后开个空间把参数拷贝过去就可以了。

析构函数的话很简单,直接释放空间即可,把其他值置一下0即可。

//构造
string(const char* s = "")
    : _size(strlen(s))
    , _capacity(_size)
{
    _str = new char[_capacity + 1];
    strcpy(_str, s);
}
//析构
~string()
{
    delete[] _str;
    _str = nullptr;
    _size = _capacity = 0;
}


遍历string

  1. 我们可以使用for循环来遍历

因为库里的string支持了[]运算符重载,我们可以就像遍历数组那样来遍历string。

int main()
{
    string s("123456");
    for (int i = 0; i < 6; i++)
    {
        cout << s[i] << " ";
    }
    cout << endl;
    return 0;
}

因为它是传引用返回的,所以我们可读可写。它重载了一个const版本,所以当你传const对象时,就只能读不能写。

int main()
{
  string s("123456");
  for (int i = 0; i < 6; i++)
  {
    s[i]++;
  }
  cout << s << endl;
  return 0;
}


  1. 使用迭代器遍历

迭代器我们可以理解为一个指针,然后需要一个范围,库里有几个函数,可以帮我们确定这个范围。


如果我们要正着遍历可以使用begin和end。

它的返回值是一个iterator的迭代器类型,然后这个类型在string类里面的,所以我们需要确定类域。

int main()
{
    string s("123456");
    string::iterator it = s.begin();
    while (it != s.end())
    {
        cout << *it << " ";
        it++;
    }
    cout << endl;
    return 0;
}

如果要倒着遍历,就需要使用了,rbegin和rend。

只不过他们的返回类型是reverse_iterator。

int main()
{
    string s("123456");
    string::reverse_iterator it = s.rbegin();
    while (it != s.rend())
    {
        cout << *it << " ";
        it++;
    }
    cout << endl;
    return 0;
}

这两对都是可读可写的,还剩两对前面带c的,是只能读,不能写。具体可戳标题详解。

  1. 使用范围for
int main()
{
  string s("123456");
  for (auto e : s)
  {
    cout << e << " ";
  }
  cout << endl;
  return 0;
}
int main()


size和length

size和length的功能是一样的,都是返回字符串的长度,和C语言的strlen很相似。

int main()
{
  string s("123456");
  cout << s.size() << endl;
  cout << s.length() << endl;
  return 0;
}

capacity

capacity是返回已经开辟的容量的大小。

int main()
{
  string s("123456");
  cout << s.capacity() << endl;
  return 0;
}

模拟实现

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


resize和reserve

  1. resize

resize可以修改size的大小。


库里重载两个版本,resize分3个版本,它可能比capacity大,也可能在size和capacity中间,也有可能比size小。如果他比capacity大的话,会扩容,并且如果我们给字符参数,就会在我们原本的字符串后面全补我们给的那个字符,直到size变成我们设置的那个,我们没给字符的话,会补‘\0’,如果在size和capacity中间,不会扩容,但是还是会补充,如果比我们的size还小的话,就充当删除的功能了。


int main()
{
  string s("123456");
  s.resize(20);
  s.resize(20,'x');
  s.resize(10);
  s.resize(4);
  return 0;
}
  1. reserve

reserve可以设置capacity的大小,如果我们知道字符串多大的话,我们可以提前开好空间,因为让系统自己自动扩容的话,可能会频繁扩容,消耗太大了,所以我们在知道需要存储的字符串多大时可以提起开好空间。


int main()
{
  string s("123456");
  cout << s.capacity() << endl;
  s.reserve(100);
  cout << s.capacity() << endl;
  return 0;
}

模拟实现

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 c = '\0')
{
    if (n <= _size)
    {
        _str[n] = '\0';
        _size = n;
    }
    else
    {
        reserve(n);
        size_t begin = _size;
        _size = n;
        while (begin < n)
        {
            _str[begin] = c;
            begin++;
        }
        _size = n;
        _str[begin] = '\0';
    }
}
相关文章
|
2月前
|
C++ 容器
|
2月前
|
C++
|
5月前
|
C语言 C++
【C++】string模拟实现(下)
本文档介绍了自定义`string`类的一些关键功能实现,包括`reserve()`用于内存管理,`push_back()`和`append()`添加字符或字符串,运算符`+=`的重载,以及`insert()`, `erase()`进行插入和删除操作。此外,还涵盖了`find()`查找函数,字符串的比较运算符重载,`substr()`获取子串,`clear()`清除内容,以及流插入和提取操作。常量`npos`用于表示未找到的标记。文档以代码示例和运行结果展示各功能的使用。
|
5月前
|
编译器 程序员 C语言
【C++】string模拟实现
这篇博客探讨了自定义实现C++ `string` 类的关键功能,包括构造、拷贝构造、赋值运算符重载及析构函数。作者强调了理解并实现这些功能对于面试的重要性。博客介绍了`string` 类的头文件`string.h`,其中定义了迭代器、基本成员函数如`swap()`、`size()`、`c_str()`等,并提到了深拷贝概念。此外,还展示了构造函数、析构函数和赋值运算符的实现,以及迭代器的定义与使用。博客还包括对C语言字符串函数的引用,以辅助读者理解实现细节。
|
6月前
|
C语言 C++
【c++】string模拟实现(2)
【c++】string模拟实现(2)
25 0
|
6月前
|
算法 C++
【c++】string模拟实现(1)
【c++】string模拟实现(1)
134 0
|
7月前
|
存储 C++
C++:String的模拟实现
C++:String的模拟实现
|
7月前
|
编译器 C++
【C++】模拟实现string
【C++】模拟实现string
|
7月前
|
存储 编译器 C++
【C++】——string的模拟实现
【C++】——string的模拟实现
|
7月前
string的模拟(下)
string的模拟(下)
54 1