STL中的string你了解吗

目录
  • 模拟实现一个string类
    • 成员变量
    • 构造函数
    • 遍历
    • 与容量相关的成员函数
    • 运算符的重载
    • 修改器
    • 常用的几个字符串函数
  • 总结

STL(standard template libaray-标准模板库):是C++标准库的重要组成部分,不仅是一个可复用的组件库,而且是一个包罗数据结构与算法的软件框架。

STL的六大组件:容器、迭代器、适配器、空间配置器、仿函数、算法。

string的行为与普通容器类似,但是并不能说它是个容器,因为无法接受所有类型的数据。

string是表示字符串的字符串类。

string在底层实际是:basic_string模板类的别名

typedef basic_string<char, char_traits, allocator>string;

头文件: #include<string>

模拟实现一个string类

首先成员变量最少需要一个字符类型的指针、字符串的大小、总共能存多少有效字符。

其次还需要构造函数、遍历的方法、增删查改、运算符重载等。

成员变量

class MyString
{
private:
	char *_str;//字符串指针
	size_t _size;//字符串大小
	size_t _capacity;//总共能存多少有效字符,不包括'\0'
	static size_t npos;//迭代器相关
}
size_t MyString:: npos = -1;

构造函数

//构造函数
MyString(const char* str = "")//缺省参数
{
	_size = strlen(str);//初始化
	_capacity = _size;
	_str = new char[_capacity + 1];//'\0'的空间+1
	strcpy(_str, str);
}
//析构函数
~MyString()
{
	delete[] _str;//释放内存
	_str = nullptr;//将指针置空
	_size = 0;//清理工作
	_capacity = 0;
}
//拷贝构造函数
MyString(const MyString& str)
{
	_size = str._size;
	_capacity = str._capacity;
	_str = new char[_capacity + 1];
	strcpy(_str, str._str);
}
//赋值运算符重载
MyString& operator=(const MyString& str)
{
	if (_str != str._str)
	{
		delete[] _str;
		_size = str._size;
		_capacity = str._capacity;
		_str = new char[_capacity + 1];
		strcpy(_str, str._str);
	}
	return *this;
}
 

遍历

1、[ ]的重载

我们在C语言中使用字符串时是可以通过[ ]进行随机访问的,所以在设计string类时,通过重载[ ]实现相同的效果。

char& operator[](size_t index)
{
	assert(index < _size&&index >= 0);
	return _str[index];
}
const char& operator[](size_t index)const
{
	assert(index < _size&&index >= 0);
	return _str[index];
}

需要两种类型的operator[ ],一个是针对非const类型对象,一个是针对const类型对象。const类型的对象是没有办法调用非const修饰*this的成员函数和重载,原因:权限扩大了。

2、迭代器

除了用[ ]来遍历类里面的字符串以外,另外的方法就是通过迭代器。

对于string的迭代器我们只需要宏定义一下

typedef char* iterator;
iterator begin()
{
	return _str;
}
iterator end()
{
	return _str + _size;
}

测试一下代码

void test_string()
{
	MyString ms;
	ms = "123";
	MyString::iterator it = ms.begin();
	while (it != ms.end())
	{
		cout << *it << endl;
		it++;
	}
}

rbegin与rend是反向迭代器,即反向遍历字符串。

前面带c的cbegin、cend等等是常字符串类型的对象

const iterator cbegin()const
{
	return _str;
}
const iterator cend()const
{
	return _str + _size;
}

与容量相关的成员函数

实现几个比较常用的函数接口

//返回字符串大小
size_t size()const
{
	return _size;
}
size_t capacity()const
{
	return _capacity;
}
//判断是否为空字符串
bool empty()const
{
	return _size == 0;
}
//更改容量
void reserve(size_t n = 0)
{
	if (n > _capacity)
	{
		char* tmp = new char[n + 1];
		strcpy(tmp, _str);
		delete[] _str;
		_str = tmp;
		_capacity = n;
	}
}
//更改大小
//resize分三种情况
void resize(size_t n = 0,char ch = '\0')
{
	if (n >= 0 && n <= _size)
	{
		_size = n;
		_str[_size] = '\0';
	}
	else if (n > _size && n <= _capacity)
	{
		for (size_t i = _size; i < n; i++)
			_str[i] = ch;
		_size = n;
		_str[_size] = '\0';
	}
	else if (n > _capacity)
	{
		reserve(n);
		for (size_t i = _size; i < n; i++)
		{
			_str[i] = ch;
		}
		_size = n;
		_str[_size] = '\0';
	}
	else
		assert(0);
}

size、capacityempty只需要设置成const类型,因为不需要修改内容。

reserve只修改_capacity的大小。

resize的实现需要分三种情况,当n的长度小于等于_size的时候,只需要修改一下_size的大小,然后把_size的位置设置为'\0'。当n的长度大于_size且小于_capacity的时候,需要新插入n-_size个ch;如果大于_capacity,说明需要重新开辟空间了,并插入n-_size个ch。

运算符的重载

1、+=的重载

平常用string类的时候发现+=进行字符串拼接很方便。

MyString& operator+=(const char* str)
{
	int len = strlen(str);
	if (len + _size > _capacity)//判断是否超出容量
	{
		reserve(len + _size);
	}
	strcpy(_str + _size, str);
	_size += len;
	return *this;
}
MyString& operator+=(char ch)
{
	if (_size == _capacity)//扩容
    {
	    size_t newcapacity = (_capacity) == 0 ? 2 : _capacity * 2;
	    reserve(newcapacity);
    }
    _str[_size] = ch;
    _size++;
    _str[_size] = '\0';//尾插过后会把'\0给覆盖了,重新在最后一个位置补一个'\0'
	return *this;
}

2、<< 和 >>的重载

为了保持和标准输入输出的使用形式是一样的,建议在类外面重载<<和>>。

//需要在类外面重载
//输出流
ostream& operator<<(ostream& out, const MyString& str)
{
	for (size_t i = 0; i < str.size(); i++)
	{
		out << str[i];
	}
	return out;
}
//输入流
istream& operator>>(istream& in, MyString& str)
{
	while (1)
	{
		char ch = in.get();
		if (ch != ' '&&ch != '\n')//cin遇到空格和'\n'会结束
		{
			str += ch;
		}
		else
			break;
	}
	return in;
}
 

补充getline函数:遇到'\n'才结束

用法:getline(cin,对象);

//getline是遇到'\n'才结束
istream& getline(istream& in, MyString& s)
{
	while (1)
	{
		char ch;
		ch = in.get();//从缓存去读入所有输入字符
		if (ch != '\n')
		{
			s += ch;
		}
		else
			break;
	}
	return in;
}

修改器

push_back尾插

void push_back(char ch)//插入一个字符,尾插
{
	if (_size == _capacity)
	{
		size_t newcapacity = (_capacity) == 0 ? 2 : _capacity * 2;
		reserve(newcapacity);
	}
	_str[_size] = ch;
	_size++;
	_str[_size] = '\0';//尾插过后会把'\0给覆盖了,重新在最后一个位置补一个'\0'
}

insert任意位置插入字符或者字符串

MyString& insert(size_t pos, const char ch)
{
	assert(pos <= _size && pos >= 0);
	if (_size == _capacity)
	{
		size_t newcapacity = _capacity == 0 ? 2 : 2 * _capacity;
		reserve(newcapacity);
	}
	int end = _size;
	while (end >= (int)pos)//为什么要强转,如果是头插,end最终=-1,
	{					   //-1和无符号比较会向无符号转变成一个32位的最大值,成为死循环
		_str[end + 1] = _str[end];
		end--;
	}
	_str[pos] = ch;
	_size++;
	return *this;
}
MyString& insert(size_t pos, const char* str)
{
	assert(pos <= _size && pos >= 0);
	size_t len = strlen(str);
	if (_size+ len > _capacity)
	{
		reserve(_capacity + len);
	}
	int end = _size;
	while (end >= (int)pos)//往后挪
	{
		_str[end + len] = _str[end];
		end--;
	}
	for (size_t i = 0; i < len; i++)
	{
		_str[pos + i] = str[i];
	}

	_size += len;
	return *this;
}

erase删除

//npos = -1(无符号整型最大值)
MyString& erase(size_t pos, size_t len = npos)
{
	assert(pos >= 0 && pos < _size);
	if (pos + len >= _size || len == npos)
	{
		_size = pos;
		_str[_size] = '\0';
	}
	else
	{
		for (size_t i = 0; i < _size - len - pos; i++)
		{
			_str[i + pos] = _str[i + pos + len];
		}
		_size -= len;
	}
	_str[_size] = '\0';
	return *this;
}

可以看出删除和任意位置插入还是挺费时间的,需要整体挪动字符串。

常用的几个字符串函数

findsubstrc_str也得掌握

find的接口比较多,可以查找string类、查找char*的字符串也可以查找单个字符

返回值为对应的下标,没找到返回npos。

substr获得一个子串,返回值为string类型

pos表示从哪里开始,len表示子串长度。

c_str 将C++的字符串类转化成C语言中char*类型。

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注我们的更多内容!

(0)

相关推荐

  • zlib库压缩和解压字符串STL string的实例详解

    zlib库压缩和解压字符串STL string的实例详解 场景 1.一般在使用文本json传输数据, 数据量特别大时,传输的过程就特别耗时, 因为带宽或者socket的缓存是有限制的, 数据量越大, 传输时间就越长. 网站一般使用gzip来压缩成二进制. 说明 1.zlib库可以实现gzip和zip方式的压缩, 这里只介绍zip方式的二进制压缩, 压缩比还是比较可观的, 一般写客户端程序已足够. 2.修改了一下zpipe.c的实现, 其实就是把读文件改为读字符串, 写文件改为写字符串即可. 例子

  • STL 的string类怎么啦

    STL 的string类怎么啦?陈皓 前言 上个周末在和我的同学爬香山闲聊时,同学说到STL中的string类曾经让他备受折磨,几年前他开发一个系统前对string类还比较清楚,然后随着程序的复杂度的加深,到了后期,他几乎对string类失去了信心和信任,他觉得他对string类一头雾水.老实说,我几年前也有同样的痛苦(就是当我写下<标准C++类string的Copy-On-Write技术>之前的一段时间).那时,我不得不研究那根本不是给人看的SGI出品的string类的源码,代码的可读性几乎

  • 一起来看看C++STL容器之string类

    目录 前言 1.标准库中的string类 2.string类的常用接口说明 2.1string对象的常见构造 2.2string类对象的容量操作 2.2.1reserve是如何开辟空间的 2.2.2clear和empty 2.2.3resize的用法 2.3string类对象的访问以及遍历操作 范围for的使用 2.4string类对象的修改操作 2.4.1push_back和append以及operator+= 2.4.2 find和rfind以及substr 2.5string非成员函数重载

  • C++STL之string类的使用

    目录 1.STL简介 (1)什么是STL (2)STL的版本 (3)如何学习STL (4)STL的六大组件 2.string类的基本概念 (1)含义 (2)使用方法 (3)原理 3.string类中常见构造函数 4.string类中析构函数 5.string类对象的容量操作 (1)显示容量 (2)扩容 6.string类中operator[]重载 (1)举例 (2)底层实现 7.string类与迭代器 (1)举例 (2)反向迭代器 (3)使用迭代的意义 (4)补充:语法糖实现遍历 8.strin

  • 关于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类 字符串的表示字符序列的类 标准的字符串类提供了对此类对象的支持,其接口类似于标准字符容器的接口,但添加了专

  • STL中的string你了解吗

    目录 模拟实现一个string类 成员变量 构造函数 遍历 与容量相关的成员函数 运算符的重载 修改器 常用的几个字符串函数 总结 STL(standard template libaray-标准模板库):是C++标准库的重要组成部分,不仅是一个可复用的组件库,而且是一个包罗数据结构与算法的软件框架. STL的六大组件:容器.迭代器.适配器.空间配置器.仿函数.算法. string的行为与普通容器类似,但是并不能说它是个容器,因为无法接受所有类型的数据. string是表示字符串的字符串类. s

  • c++中的string常用函数用法总结

    标准c++中string类函数介绍 注意不是CString之所以抛弃char*的字符串而选用C++标准程序库中的string类,是因为他和前者比较起来,不必 担心内存是否足够.字符串长度等等,而且作为一个类出现,他集成的操作函数足以完成我们大多数情况下(甚至是100%)的需要.我们可以用 = 进行赋值操作,== 进行比较,+ 做串联(是不是很简单?).我们尽可以把它看成是C++的基本数据类型. 好了,进入正题---首先,为了在我们的程序中使用string类型,我们必须包含头文件 <string>

  • 关于STL中set容器的一些总结

    1.关于set C++ STL 之所以得到广泛的赞誉,也被很多人使用,不只是提供了像vector, string, list等方便的容器,更重要的是STL封装了许多复杂的数据结构算法和大量常用数据结构操作.vector封装数组,list封装了链表,map和set封装了二叉树等,在封装这些数据结构的时候,STL按照程序员的使用习惯,以成员函数方式提供的常用操作,如:插入.排序.删除.查找等.让用户在STL使用过程中,并不会感到陌生. 关于set,必须说明的是set关联式容器.set作为一个容器也是

  • STl中的排序算法详细解析

    1. 所有STL sort算法函数的名字列表: 函数名    功能描述 sort   对给定区间所有元素进行排序 stable_sort 对给定区间所有元素进行稳定排序 partial_sort 对给定区间所有元素部分排序 partial_sort_copy    对给定区间复制并排序 nth_element 找出给定区间的某个位置对应的元素 is_sorted               判断一个区间是否已经排好序 partition     使得符合某个条件的元素放在前面 stable_pa

  • 浅谈c++中的stl中的map用法详解

    Map是STL的一个关联容器,它提供一对一(其中第一个可以称为关键字,每个关键字只能在map中出现一次,第二个可能称为该关键字的值)的数据处理能力,由于这个特性,它完成有可能在我们处理一对一数据的时候,在编程上提供快速通道.这里说下map内部数据的组织,map内部自建一颗红黑树(一种非严格意义上的平衡二叉树),这颗树具有对数据自动排序的功能,所以在map内部所有的数据都是有序的,后边我们会见识到有序的好处. 下面举例说明什么是一对一的数据映射.比如一个班级中,每个学生的学号跟他的姓名就存在着一一

  • 关于STL中的map容器的一些总结

    一.关于map的介绍 map是STL的一个容器,和set一样,map也是一种关联式容器.它提供一对一(其中第一个可以称为关键字,每个关键字只能在map中出现一次,第二个可能称为该关键字的值)的数据处理能力,由于这个特性,有助于我们处理一对一数据.这里说下map内部数据的组织,map内部是自建一颗红黑树(一种非严格意义上的平衡二叉树),这颗树具有对数据自动排序的功能,所以在map内部所有的数据都是有序的.学习map我们一定要理解什么是一对一的数据映射?比如:一个班级中,每个学生的学号跟他的姓名就存

  • C++中的string类(C++字符串)入门完全攻略

    前言 string 类是 STL 中 basic_string 模板实例化得到的模板类.其定义如下: typedef basic_string <char> string; basic_string 此处可以不必深究. string 类的成员函数有很多,同一个名字的函数也常会有五六个重载的版本.篇幅所限,不能将这些原型一一列出并加以解释.这里仅对常用成员函数按功能进行分类,并直接给出应用的例子,通过例子,读者可以基本掌握这些成员函数的用法. 要想更深入地了解 string 类,还要阅读 C++

  • C++中的STL中map用法详解(零基础入门)

    目录 一.什么是 map ? 二.map的定义 2.1 头文件 2.2 定义 2.3 方法 三.实例讲解 3.1 增加数据 3.2 删除数据 3.3 修改数据 3.4 查找数据 3.5 遍历元素 3.6 其它方法 四.总结 map 在编程中是经常使用的一个容器,本文来讲解一下 STL 中的 map,赶紧来看下吧! 一.什么是 map ? map 是具有唯一键值对的容器,通常使用红黑树实现. map 中的键值对是 key value 的形式,比如:每个身份证号对应一个人名(反过来不成立哦!),其中

  • 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++ STL中五个常用算法使用教程及实例讲解

    目录 前言 sort()排序 常用遍历算法for_each() 常用遍历算法 搬运transform() 查找算法find 删除操作erase() 实例应用 前言 在C++中使用STL算法都要包含一个算法头文件 #include<algorithm> 这样我们才能使用这个STL算法函数 sort()排序 Sort函数包含在头文件为#include<algorithm>的c++标准库中,是一个专门用来排序的高效的函数,我们在解决问题时可以方便快捷的排列顺序. sort()函数中有三个

随机推荐