关于C++STL string类的介绍及模拟实现

目录
  • 一、标准库中的string类
    • 1.string类
    • 2.string类中的常用接口说明+模拟实现
      • 2.1 string类对象的常见构造+模拟实现
      • 2.2 string类对象的容量操作+模拟实现
      • 2.3 string类对象的访问及遍历操作+模拟实现
      • 2.4 string类对象的修改操作+模拟实现
      • 2.5 string类非成员函数+模拟实现

一、标准库中的string类

1.string类

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

2.string类中的常用接口说明+模拟实现

2.1 string类对象的常见构造+模拟实现

代码演示:

#include<iostream>
#include<string>
using namespace std;

int main()
{
 string s1;
 string s4("hello world");
 string s5("hello world", 7);
 string s6(10, 'x');
 string s2(s4);
 string s3(s4, 6, 3);

 cout << "s1:"<< s1.c_str() << endl;
 cout << "s4:" << s4.c_str() << endl;
 cout << "s5:" << s5.c_str() << endl;
 cout << "s6:" << s6.c_str() << endl;
 cout << "s2:" << s2.c_str() << endl;
 cout << "s3:" << s3.c_str() << endl;
}

运行结果:

模拟实现

由于上面有些接口不常用,所以我就模拟实现了一部分常用的接口

string (const char* s)

namespace cxy
{
 class string
 {
 public:
  string(const char*s = "")
  {
   if (s==nullptr)
    return;
   _size = strlen(s);
   _capacity = _size;
   _str = new char[_capacity + 1];
   strcpy(_str, s);
  }

  const char* c_str()
  {
   return _str;
  }
 private:
  size_t _size;
  size_t _capacity;
  char* _str;
 };
}

string (const string& str)
void swap (string& str)

namespace cxy
{
 class string
 {
 public:
  void swap(string& str)
  {
  //下面的swap会调用库里面的接口
   ::swap(_size, str._size);
   ::swap(_capacity, str._capacity);
   ::swap(_str, str._str);
  }

  string(const char*s = "")
  {
   if (s==nullptr)
    return;
   _size = strlen(s);
   _capacity = _size;
   _str = new char[_capacity + 1];

   strcpy(_str, s);
  }

  string(const string& str)
   :_str(nullptr), _size(0), _capacity(0)
  {
   string tmp(str._str);
   swap(tmp);
  }

  char* c_str()
  {
   return _str;
  }

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

2.2 string类对象的容量操作+模拟实现

代码演示:

int main()
{
 string s1("hello world");
 cout <<"s1.size(): " <<s1.size() << endl;
 cout <<"s1.length(): "<< s1.length() << endl;
 cout <<"s1.capacity(): "<<s1.capacity() << endl;
 cout <<"s1:"<< s1 << endl;
 cout << endl;

 s1.clear();
 cout <<"s1:"<< s1 << endl;
 cout << "s1.size(): " << s1.size() << endl;
 cout << "s1.capacity(): " << s1.capacity() << endl;
 cout << endl;

 s1 = "hello world";
 cout << "s1:" << s1 << endl;
 cout << "s1.size(): " << s1.size() << endl;
 cout << "s1.capacity(): " << s1.capacity() << endl;
 s1.resize(17,'x');
 //当n>capacity,则扩容,并且把0~27上位置的空余位置填充‘字符'
 cout << "s1:" << s1 << endl;
 cout << "s1.size(): " << s1.size() << endl;
 cout << "s1.capacity(): " << s1.capacity() << endl;
 s1.resize(27, 'x');
 //当size<n<capacity,则把0~27上位置的空余位置填充‘字符'
 cout << "s1:" << s1 << endl;
 cout << "s1.size(): " << s1.size() << endl;
 cout << "s1.capacity(): " << s1.capacity() << endl;
 s1.resize(5, 'x');
 //当n<size,则只保留n个‘字符',空间大小不变
 cout << "s1:" << s1 << endl;
 cout << "s1.size(): " << s1.size() << endl;
 cout << "s1.capacity(): " << s1.capacity() << endl;
 cout << endl;

 string s2("hello world");
 s2.reserve(5);
 //当n<=capacity时,空间大小不变,且不改变数据内容
 cout << "s2:" << s2 << endl;
 cout << "s2.size(): " << s2.size() << endl;
 cout << "s2.capacity(): " << s2.capacity() << endl;

 s2.reserve(100);
 //当n>capacity时,空间会增大
 cout << "s2:" << s2 << endl;
 cout << "s2.size(): " << s2.size() << endl;
 cout << "s2.capacity(): " << s2.capacity() << endl;
}

运行结果:

得知:

reserve和resize的区别:reserve不会影响内容,resize会影响内容。

模拟实现

size_t size() const
返回字符串的有效长度

namespace cxy
{
 class string
 {
 public:
  size_t size()const
  {
   return _size;
  }
 private:
  size_t _size;
  size_t _capacity;
  char* _str;
 };
}

size_t capacity() const
返回空间的大小

namespace cxy
{
 class string
 {
 public:
  size_t capacity()const
  {
   return _capacity;
  }
 private:
  size_t _size;
  size_t _capacity;
  char* _str;
 };
}

bool empty() const
检测字符串释放为空串,是返回true,否则返回false

namespace cxy
{
 class string
 {
 public:
  bool empty()const
  {
   return _str == 0;
  }
 private:
  size_t _size;
  size_t _capacity;
  char* _str;
 };
}

void clear()
清空有效字符 ,不会改变容量

namespace cxy
{
 class string
 {
 public:
  void clear()
  {
   _size = 0;
   _str[_size] = '\0';
  }
 private:
  size_t _size;
  size_t _capacity;
  char* _str;
 };
}

void reserve (size_t n = 0)
请求改变容量 ,此功能对字符串长度没有影响,无法改变其内容

如果 n 大于当前字符串容量,则该函数会导致容器将其容量增加到 n 字符(或更大)
n小于当前字符串容量时,不会发生改变

namespace cxy
{
 class string
 {
 public:
  void reserve(size_t n=0)
  {
   if (n > _capacity)
   {
    char *tmp = new char[n + 1];
    strncpy(tmp,_str,_size+1);
    delete[]_str;

    _str = tmp;
    _capacity = n;
   }
 private:
  size_t _size;
  size_t _capacity;
  char* _str;
 };
}

补充:strncpy是C语言中的函数

char * strncpy ( char * destination, const char * source, size_t num )

功能:

  • 将source中的字符串复制到destination中,且复制num个字符个数,如果在没有复制完num个字符之前,找到了source的末尾,则目标填充零,直到向其编写了总共num字符。
  • 如果来source中的字符有效长度大于数字,则目的地末尾不会隐含任何空字符('\0')。
  • 因此,在这种情况下,目的地不应被视为无效终止的 C 字符串(因此读取它将溢出,所以这种时候记得要在末尾添加'\0')。

void resize (size_t n, char c)
void resize (size_t n)
将有效字符的个数该成n个,多出的空间用字符c填充

  • 将字符串大小重新变为n字符的长度。
  • 如果 n 小于当前字符串长度,则当前值将缩短为其第一个 n 字符,从而删除 n 之外的字符。
  • 如果 n 大于当前字符串长度,则通过在末尾插入尽可能多的字符c以达到 n 的大小来扩展当前内容。
  • 如果指定c,则新元素初始化为c的副本,否则,它们是值初始化字符(空字符)。
namespace cxy
{
 class string
 {
 public:
  void resize(size_t n,char c='\0')
  {
   if (n<_size)
   {
    _size = n;
    _str[_size] = '\0';
   }
   else
   {
    if (n > _capacity)
    {
     reserve(n);
    }
    memset(_str + _size, c, n - _size);
    _size = n;
    _str[_size] = '\0';
   }
 private:
  size_t _size;
  size_t _capacity;
  char* _str;
 };
}

补充:memset是C语言中的函数

void * memset ( void * ptr, int value, size_t num )

功能:

  • 将value传到prt中,以第一个位置开始传,传num个,传完为止。

总结

  • size()与length()方法底层实现原理完全相同,引入size()的原因是为了与其他容器的接口保持一致,一般情况下基本都是用size()。
  • clear()只是将string中有效字符清空,不改变底层空间大小。
  • resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不同的是当字符个数增多时:resize(n)用0来填充多出的元素空间,resize(size_t n, char c)用字符c来填充多出的元素空间。注意:resize在改变元素个数时,如果是将元素个数增多,可能会改变底层容量的大
  • reserve(size_t res_arg=0):为string预留空间,不改变有效元素个数,当reserve的参数小于string的底层空间总大小时,reserver不会改变容量大小。

2.3 string类对象的访问及遍历操作+模拟实现

代码演示:

int main()
{
 string s("hello world");
 cout << "operator[] :";
 for (size_t i = 0; i < s.size(); i++)
  cout << s[i] ;
 cout << endl;
 //迭代器
 string::iterator it = s.begin();
 cout << "iterator :";
 while (it != s.end())
 {
  cout << *it ;
  ++it;
 }
 cout << endl;
 //范围for
 cout << "范围for :";
 for (auto ch : s)
 {
  cout << ch ;
 }
 cout << endl;
}

模拟实现

const char& operator[] (size_t pos) const

namespace cxy
{
 class string
 {
 public:
  const char& operator[](size_t pos)const
  {
   assert(pos < _size);
   return _str[pos];
  }
 private:
  size_t _size;
  size_t _capacity;
  char* _str;
 };
}

iterator begin()    iterator end()

namespace cxy
{
 class string
 {
 public:
  typedef char* iterator;
  iterator begin()
  {
   return _str;
  }
  iterator end()
  {
   return _str+_size;
  }
 private:
  size_t _size;
  size_t _capacity;
  char* _str;
 };
}

C++11:范围for

在这里不实现,知道怎么用就行

2.4 string类对象的修改操作+模拟实现

代码演示:

int main()
{
 string s("hello world");
 s.push_back('K');
 cout << s << endl;
 s.append("SSSSS");
 cout << s << endl;
 s += "FF";
 cout << s << endl;
 cout << s.find("KSS") << endl;
 s.erase(11, 8);
 cout << s << endl;
}

运行结果:

模拟实现:只实现了一些常用的接口

void push_back (char c)
在字符串后面插入字符c

namespace cxy
{
 class string
 {
 public:
  void push_back(char c)
  {
   if (_size == _capacity)
   {
    reserve(_capacity * 2);
   }
   _str[_size] = c;
   _str[_size+1] = '\0';
   _size++;
  }
 private:
  size_t _size;
  size_t _capacity;
  char* _str;
 };
}

string& append (const char*s)
在字符串后面追加字符串s

namespace cxy
{
 class string
 {
 public:
  string &append(const char*s)
  {
   size_t len = strlen(s)+_size;
   if (len > _capacity)
   {
    reserve(len);
   }
   strncpy(_str + _size, s, len - _size+1);
   _size = len;
   return *this;
  }
 private:
  size_t _size;
  size_t _capacity;
  char* _str;
 };
}

string& operator+= (const char* s)
在字符串后面追加字符串s

namespace cxy
{
 class string
 {
 public:
  string& operator+=(const char*s)
  {
   append(s);
   return *this;
  }
 private:
  size_t _size;
  size_t _capacity;
  char* _str;
 };
}

const char* c_str() const
返回c格式的字符串

namespace cxy
{
 class string
 {
 public:
  const char* c_str()const
  {
   return _str;
  }
 private:
  size_t _size;
  size_t _capacity;
  char* _str;
 };
}

size_t find (const char* s, size_t pos = 0) const
从字符串pos位置开始往后找字符串s,返回该字符串s在字符串中的位置

namespace cxy
{
 class string
 {
 public:
  size_t find(const char*s,size_t pos=0)const
  {
   char *str = _str+pos;
   while (*str)
   {
    char* str_s = str;
    const char* tmp = s;
    while (*str_s&&*tmp==*str_s)
    {
     tmp++;
     str_s++;
    }
    if (*tmp=='\0')
     return str - _str;
    else
     str++;
   }
   return -1;
  }
 private:
  size_t _size;
  size_t _capacity;
  char* _str;
 };
}

string& erase (size_t pos = 0, size_t len = npos)
擦除字符串的一部分,减少其长度

static const size_t npos = 0;

namespace cxy
{
 class string
 {
 public:
  string &erase(size_t pos = 0, size_t len = npos)
  {
   assert(pos < _size);

   if (len+pos >= _size)
   {
    _str[pos] = '\0';
    _size = pos;
   }
   else
   {
    strcpy(_str + pos, _str + pos + len);
    _size -= len;

   }
   return *this;
  }
 private:
  size_t _size;
  size_t _capacity;
  char* _str;
 };
}

2.5 string类非成员函数+模拟实现

模拟实现

istream& operator>> (istream& is, string& str)

namespace cxy
{
 class string
 {
 public:

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

 istream& operator >> (istream& is, string& str)
 {
  str.clear();
  char ch;
  ch = is.get();
  while (ch != ' '&&ch != '\0')
  {
   str += ch;
   ch = is.get();
  }
  return is;
 }
}

说明一下:这个函数实现放在全局,是因为他的is要和对象str抢第一个位置,如果放在string类里面实现,那么第一个位置是this指针,也就是str对象,在用这个函数的时候就会很变扭。

ostream& operator<< (ostream& os, const string& str);

namespace cxy
{
 class string
 {
 public:

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

 ostream& operator<< (ostream& os, string& str)
 {
  for (auto ch:str)
  {
   os << ch;
  }
  return os;
 }
}

istream& getline (istream& is, string& str)
获取一行字符串

namespace cxy
{
 class string
 {
 public:

 private:
  size_t _size;
  size_t _capacity;
  char* _str;
 };
 istream&getline(istream&is ,string&s)
 {
  s.clear();
  char ch;
  ch = is.get();
  while (ch != '\0')
  {
   s += ch;
   ch = is.get();
  }
  return is;
 }
}

到此这篇关于 关于C++STL string类的介绍及模拟实现的文章就介绍到这了,更多相关C++STL string类介绍及模拟实现内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++ string字符串的修改与替换方法详析

    字符串内容的变化包括修改和替换两种.本节将分别讲解字符串内容的修改和字符串内容的替换. 字符串内容的修改 可以通过使用多个函数修改字符串的值.例如 assign(),operator=,erase(),交换(swap),插入(insert)等.另外,还可通过 append() 函数添加字符. 下面逐一介绍各成员函数的使用方法. assign()函数 使用 assign() 函数可以直接给字符串赋值.该函数既可以将整个字符串赋值给新串,也可以将字符串的子串赋值给新串.其在 basic_string

  • C++之string类对象的容量操作详解

    目录 前言 1. size返回字符串的有效长度 2. length 返回字符串的有效长度 3. capacity 返回总空间的大小 4. empty 检测是否为空串 5. clear 清空有效字符 6. resize 修改个数并填充 7. reserve 为字符串预留空间 总结 前言 hello,大家好,今天这期文章我们用来介绍string类对象的容量操作.希望对大家有所帮助,让我们开始吧. 1. size返回字符串的有效长度 返回字符串的长度,以字节为单位.这是符合字符串内容的实际字节数,不一

  • c++ string的erase删除方法

    之前不是很清楚c++中string如何删除元素,现在记录一下. (参考自 c++ primer plus 第六版 模版类 string) string中提供的成员函数可以用来删除字符串中的字符,这里主要介绍erase方法 erase方法原型 1. basic_string & erase(size_type pos=0, size_type n=npos); 即从给定起始位置pos处开始删除, 要删除字符的长度为n, 返回值修改后的string对象引用 示例[1] #include<iost

  • C++string容器基本概念详解

    string基本概念 本质: string是C++风格的字符串,而string本质上是一个类 string和char*区别: char*是一个指针 string是一个类,类内部封装了char*,管理这个字符串,是一个char*型的容器. 特点: string类内部封装了很多成员方法 例如:查找find,拷贝copy,删除delete,替换replace,插入insert string管理char*所分配的内存,不用担心复制越界和取值越界等,由类内部进行负责. string构造函数 #includ

  • c++ STL常用遍历算法

    需要引入头文件#include<algorithm> 1.for_each #include<iostream> using namespace std; #include <vector> #include <algorithm> class MyPrint { public: void operator()(int val) const{ cout << val << " "; } }; void printV

  • C++ STL 序列式容器与配接器的简单使用

    目录 容器概述 序列式容器 array vector list deque forward_list Adapter(配接器) stack queue priority_queue 容器概述 C++标准里提供了以下容器或容器配接器: 序列式容器 配接器 关联式容器 不定序关联容器 array stack set unordered_set vector queue map unordered_map list priority_queue multiset unordered_multiset

  • C++ string替换指定字符实例代码

    前言 C++的string提供了replace方法来实现字符串的替换,但是有时候我们想要实现类似JAVA中的替换功能--将string中的某个字符a全部替换成新的字符b,这个功能在提供的replace方法中并没有实现. 不过只要再深入了解一下STL,就可以在变易算法中找到解决方案--使用#include<algorithm>中的replace算法即可. 测试代码如下: #include<algorithm> #include<string> #include<io

  • C++中string转换为char*类型返回后乱码问题解决

    问题来源: 在写二叉树序列化与反序列化时发现序列化函数为char* Serialize1(TreeNode *root)  其函数返回类型为char*,但是我在实现的过程中为了更方便的操作添加字符串使用的是C++中string类型的变量,这就导致我最后得到的结果res是string类型,若是要返回需要转化为char *类型.而等我将string类型转为char*后返回在主函数中就成了乱码. 先直接说最后的解决办法: 第一种:定义一个char数组,数组长度为stringlength+1,将stri

  • 深入探究C++ string的内部究竟是什么样的

    在C语言中,有两种方式表示字符串: 一种是用字符数组来容纳字符串,例如char str[10] = "abc",这样的字符串是可读写的: 一种是使用字符串常量,例如char *str = "abc",这样的字符串只能读,不能写. 两种形式总是以\0作为结束标志. C++ string 与它们在C语言中的前身截然不同.首先,也是最重要的不同点,C++ string 隐藏了它所包含的字符序列的物理表示.程序设计人员不必关心数组的维数或\0方面的问题. string 在内

  • C++ STL中常见的算法使用方式

    目录 什么是STL? 0. < algorithm> 是什么: 1. Non-modifying sequence operations: 1.1 find:(Find value in range) 1.2 count:(Count appearances of value in range) 1.3 equal:(Test whether the elements in two ranges are equal) 1.4 search:(Search range for subsequen

  • C++ 字符串string和整数int的互相转化操作

    一.string转int的方式 1.采用最原始的string, 然后按照十进制的特点进行算术运算得到int,但是这种方式太麻烦,这里不介绍了. 2.采用标准库中atoi函数. string s = "12"; int a = atoi(s.c_str()); 对于其他类型也都有相应的标准库函数,比如浮点型atof(),long型atol()等等. 3.采用sstream头文件中定义的字符串流对象来实现转换. istringstream is("12"); //构造输

  • C++中string替换所有指定字符串的方法

    C++的string提供了replace方法来实现字符串的替换,但是对于将字符串中某个字符串全部替换这个功能,string并没有实现,我们今天来做的就是这件事. 首先明白一个概念,即string替换所有字符串,将"12212″这个字符串的所有"12″都替换成"21″,结果是什么? 可以是22211,也可以是21221,有时候应用的场景不同,就会希望得到不同的结果,所以这两种答案都做了实现,代码如下: # include # include using namespace st

  • C++ stringstream类用法详解

    本文主要介绍 C++ 中 stringstream 类的常见用法. 1 概述 <sstream> 定义了三个类:istringstream.ostringstream 和 stringstream,分别用来进行流的输入.输出和输入输出操作.本文以 stringstream 为主,介绍流的输入和输出操作. <sstream> 主要用来进行数据类型转换,由于 <sstream> 使用 string 对象来代替字符数组(snprintf方式),就避免缓冲区溢出的危险:而且,因

  • C++ string格式化输出方式

    flyfish 利用boost的format 头文件 #include <boost/format.hpp> boost::format f = boost::format("%.2f %s %d") % 1.234 %"123" % 12; std::string s = f.str(); 等同于 boost::format f = boost::format("%.2f %s %d"); f % 1.234 %"123&

随机推荐