广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >STL中的string你了解吗
  • 747
分享到

STL中的string你了解吗

2024-04-02 19:04:59 747人浏览 泡泡鱼
摘要

目录模拟实现一个string类成员变量构造函数遍历与容量相关的成员函数运算符的重载修改器常用的几个字符串函数总结STL(standard template libaray-标准模板库

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*类型。

总结

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

--结束END--

本文标题: STL中的string你了解吗

本文链接: https://www.lsjlt.com/news/143577.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • STL中的string你了解吗
    目录模拟实现一个string类成员变量构造函数遍历与容量相关的成员函数运算符的重载修改器常用的几个字符串函数总结STL(standard template libaray-标准模板库...
    99+
    2022-11-13
  • STL中vector的使用你了解吗
    目录前言1.vector是什么2.vector创建对象3.遍历vector(1)下标遍历(2)迭代器遍历(3)范围for遍历3.vector容量函数4.vector的扩容函数5.ve...
    99+
    2022-11-13
  • redis中的bitmap你了解吗
    目录1、BitMap是什么2、setbit命令介绍 总结1、BitMap是什么 通过一个bit位来表示某个元素对应的值或者状态,其中的key就是对应元素本身。我们知道8个b...
    99+
    2022-11-13
  • 一篇文章带你了解C++(STL基础、Vector)
    目录STL基本概念STL六大组件STL中容器、算法、迭代器容器算法迭代器初识Vector容器Vector三大遍历算法Vector存放其他数据类型 Vector容器嵌套总结S...
    99+
    2022-11-12
  • 你了解php中pcntl_fork吗
    小编给大家分享一下你了解php中pcntl_fork吗,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!pcntl_fork()函数是php-pcntl模块中用于创建...
    99+
    2023-06-15
  • JavaScript中的预解析你了解吗
    JS的预解析是指在代码执行之前,JavaScript引擎会先对代码进行一次扫描,将变量声明和函数声明提升到当前作用域的顶部,以便在代码执行时能够正确地访问这些变量和函数。这个过程也被...
    99+
    2023-05-20
    JavaScript预解析学习 JavaScript预解析使用 JavaScript预解析
  • 你了解Java中的Object类吗
    任何一个类默认继承Object类,就算没有直接继承,最终也会间接继承。 Object类,有两种方式找到: 第一种:在源码当中找到 第二种:查阅java类库的帮助文档...
    99+
    2022-11-12
  • python中的getter与setter你了解吗
    目录前言复制型编写使用python的装饰器总结前言 因为java开发的习惯,想要在python开发中使用类似JavaBean的结构。 复制型编写 在python可以直接结合java中...
    99+
    2022-11-13
  • react中的axios模块你了解吗
    目录一、react中axios模块的使用1、基于Promise的HTTP库用在浏览器和node.js中2、创建XMLHttpRequest对象:3、在react中安装axios4、发...
    99+
    2022-11-13
  • React中的Diff算法你了解吗
    目录一、Diff算法的作用二、React的Diff算法  1、什么是调和?2、什么是React diff算法?3、diff策略4、tree diff:5、comp...
    99+
    2022-11-13
  • Spring中的AOP操作你了解吗
    目录一、AOP操作术语 1. 连接点2. 切入点3. 通知(增强)4. 切面二、AOP操作2.1 切入点表达式2.2 AOP操作(AspectJ 注解方式)2.3 相同切入...
    99+
    2022-11-13
  • Java中的内部类你了解吗
    目录成员内部类1.定义2.成员内部类的使用规则 3.成员内部类对象的创建:4.内部类与静态域静态内部类:1.定义:2.静态内部类的使用规则:3.静态内部类对象的创建&nbs...
    99+
    2022-11-13
  • SpringCloud的@RefreshScope 注解你了解吗
    目录pom.xmlproperties启动类配置类controller打包springcloud对应的springboot版本参考:总结 spring-boot-starter-ac...
    99+
    2022-11-12
  • Golang中的泛型你真的了解吗
    目录什么是泛型为什么需要泛型泛型语法类型参数类型集类型推断总结Golang 在 1.18 版本更新后引入了泛型,这是一个重要的更新,Gopher 万众瞩目,为 Golang 带来了更...
    99+
    2023-05-20
    Golang泛型用法 Golang泛型学习 Golang泛型 Go 泛型
  • MySQL的索引你了解吗
    目录一、索引介绍二、索引优缺点三、索引结构1. 经典B+树2. MySQL中B+树索引3. Hash索引4. 为什么InnoDB选择B+树索引?   四、索引分类五、索引语法六、SQ...
    99+
    2022-11-13
  • python的rllib库你了解吗
    目录urllib库作用Urllib 库下的几种模块的基本使用一、urllib.request模块1.功能2.常用方法参数说明:总结urllib库作用 urllib 库 是Python...
    99+
    2022-11-12
  • React中的Refs属性你来了解吗
    目录1 介绍2 使用方法2.1 createRef(版本>=React16.3)2.2 回调Refs2.3 String类型的Refs(已过时,不推荐使用)2.4 useRef...
    99+
    2022-11-13
  • TypeScript中的函数和类你了解吗
    目录函数作为参数定义函数函数参数的类型可选类型参数默认值剩余参数this的默认推导函数重载类初始化继承多态成员修饰符总结函数 以下声明了一个函数类型,通过type来定义类型别名,vo...
    99+
    2022-11-13
  • Python基础中的列表你了解吗
    目录1.列表定义:2.列表创建和删除使用赋值运算符直接创建列表创建空列表创建数值列表删除列表3.访问列表元素练习总结1.列表定义: 形式上,列表的所有元素都放在一对中括号"...
    99+
    2022-11-13
  • Python标准库中的sys你了解吗
    目录sys作用常用变量sys.versionsys.maxsizesys.maxunicodesys.pathsys.platformsys.argvsys.executablesy...
    99+
    2022-11-13
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作