C++模板类string那点事儿

2021/7/25 11:39:05

本文主要是介绍C++模板类string那点事儿,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

C++模板类string那点事儿

      • 初识string
      • 常用string接口
        • 迭代器
        • reserve和resize
      • 模拟实现string增删查改
          • 尾插
          • 头插/中间插入
      • string相关算法

初识string

string是STL(Standard Template Library)标准模板库提供的一个容器,官方定义如下:

在这里插入图片描述

在这里插入图片描述
可见string只是basic_string的一个模板类。

常用string接口

接口说明
string(const string& str)拷贝构造函数
string()无参构造函数
string(char*)使用C字符串的构造函数
begin()返回开头的迭代器
end()返回结尾的迭代器
rbegin()begin的反向迭代器
rend()end的反向迭代器
operator+=+=重载,常用
erase清空指定长度字符串
insert插入,效率低,因为底层用的是数组
reserve申请改变容器容量
reseze改变字符串长度
c_str返回原生C字符串,导致不能用==等操作符比较两个字符串

迭代器

迭代器(iterator)可以将它看作是类似于指针的东西,使用迭代器的遍历方式如下:

string::iterator it = s.begin();
while(it != s.end())
{
	std::cout << *it << " ";
}

迭代器又分为普通迭代器(iterator)和常量迭代器(const_iterator),常量迭代器不能改变对象。迭代器的一个用处就是用于遍历,遍历可以用[ ],但是并不是所有容器都支持,比如list、map。所以迭代器是一种统一的方式。

需要注意的是,C++提供的的迭代器一般都是左闭右开的区间,也就是[begin(), end()),其中end()返回的是最后一个数据的下一个位置的迭代器。

使用erase()时,也可以传入一个迭代器,进行删除字符操作。

string str = "hello";
string::iterator it = str.begin();

while(it != str.end())
{
	str.erase(it);
}

因为删除操作底层实现是通过后面元素往前挪动的,所以这里不需要改变迭代器。只需要让迭代器始终指向第一个元素即可。

使用迭代器进行字符串容器操作时,是会失效的。例如两个字符串对象交换等。

reserve和resize

reserve调整字符串容器容量,当调整的容量大于已有的容器容量时,会扩容;调整的容量小于已有空间容量时,容量不会减小。resize则没有这种问题。

模拟实现string增删查改

尾插

在字符串尾部增加一个字符时,首先先检查字符串容量是否允许添加一个字符,如果不允许,就增加字符串容量。当容量为0时,就指定一个新容量大小,容量不为0时,容量就增加为原来的2倍。

扩容后,再添加字符,并且在字符串最后添加’\0’,最后数组长度加一。

void hsy::string::push_back(char c)
{
	if (_size + 1 > _capacity)
	{
		size_t new_capacity = _capacity == 0 ? 4 : _capacity * 2;
		reserve(new_capacity);
	}

	_str[_size] = c;
	_str[_size + 1] = '\0';
	_size++;
}

在字符串尾部添加字符串时,同样要先检查字符串容量大小,当添加的字符串加上原来字符串长度大于容量时,就扩容,然后将字符串拷贝到原有的字符串数组,最后更新字符串长度。

void hsy::string::append(const char* str)
{
	size_t len = strlen(str) + _size;
	if (len > _capacity)
	{
		reserve(len);
	}
	
	strcpy(_str + _size, str);
	_size = len;
}
头插/中间插入

将一个字符插入字符串指定位置,需要挪动该位置及其之后的数据,然后再将待插入字符填入指定位置。

同样地,首先在插入之前要检查容量。在数据挪动时,是将end指针指向字符串’\0’后面的那个位置,然后将pos位置及之后的数据往后移动一位,最后填入字符c。

hsy::string& hsy::string::insert(size_t pos, char c)
{
	assert(pos < _size);
	if (_size == _capacity)
	{
		size_t new_capacity = _capacity == 0 ? 4 : _capacity * 2;
		reserve(new_capacity);
	}
	
	int end = _size + 1;
	while (end > pos)
	{
		_str[end] = _str[end - 1];
		end--;
	}
	_str[pos] = c;
	_size++;

	return *this;
}

插入一个字符串,同样需要先挪出len个空间,然后将字符串拷贝到腾出的空间。

hsy::string& hsy::string::insert(size_t pos, const char* str)
{
	assert(pos < _size);

	size_t len = strlen(str);
	if (_size + len > _capacity)
	{
		reserve(_size + len);
	}

	char* end = _str + _size;
	while (end >= _str + pos)
	{
		*(end + len) = *end;
		end--;
	}

	strncpy(_str + pos, str, len);
	_size += len;

	return *this;
}

删除字符串时,需要考虑从指定位置开始删除,当删除的长度len超过从pos位置到字符串结尾时,只需要在pos位置添’\0’。当删除的长度len小于从pos到字符串结尾时,需要将pos+len开始的字符往前拷贝到pos位置。

hsy::string& hsy::string::erase(size_t pos, size_t len)
{
		assert(pos < _size);
		size_t leftLen = _size - pos;
		if (len >= leftLen)
		{
			_str[pos] = '\0';
			_size = pos;
		}
		else
		{
			strcpy(_str + pos, _str + pos + len);
			_size -= len;
		}

		return *this;
	}

// 返回c在string中第一次出现的位置

size_t hsy::string::find(char c, size_t pos) const
{
	for (size_t i = pos; i < _size; i++)
	{
		if (_str[i] == c)
		{
			return i;
		}
	}
	return -1;
}

// 返回子串s在string中第一次出现的位置

size_t hsy::string::find(const char* s, size_t pos) const
{
	char* ret;
	if ((ret = strstr(_str + pos, s)) != NULL)
	{
		return ret - _str;
	}

	return -1;
}

通过[ ]操作符重载,可以对字符串索引同时改变内容。

//只读
const char& hsy::string::operator[](size_t index) const
{
	assert(index < _size);

	return _str[index];
}
//可读可写
char& hsy::string::operator[](size_t index)
{
	assert(index < _size);

	return _str[index];
}

string相关算法

代码链接



这篇关于C++模板类string那点事儿的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程