模拟string(二)详解

目录

  • void reserve(size_t n)扩容实现
    • 代码
  • void insert(size_t pos, char ch)字符前插
    • 错误写法
    • 代码
  • void insert(size_t pos, const char* str)在指定位置插入字符串
    • 错误写法
    • 代码
  • void push_back(char ch)字符尾差
    • 写法一
    • 写法二
  • void append(const char* str)字符串尾差
    • 写法一
    • 写法二
  • string& operator+=(char ch)字符+=
    • 代码
  • string& operator+=(const char* str)字符串+=
    • 代码

感谢各位大佬对我的支持,如果我的文章对你有用,欢迎点击以下链接
🐒🐒🐒 个人主页
🥸🥸🥸 C语言
🐿️🐿️🐿️ C语言例题
🐣🐣🐣 python
🐓🐓🐓 数据结构C语言
🐔🐔🐔 C++
🐿️🐿️🐿️ 文章链接目录

void reserve(size_t n)扩容实现

void reserve(size_t n)我们需要先判断如果传入的n值是大于或等于_capacity时,就代表需要扩容,这里的扩容我们用new来扩容

new扩容的方式就先用一个char*的tmp类型指针,然后new开辟一块空间,空间大小为n个字节

因为new开辟的空间是没有数据的,所以我们需要将_str的数据拷贝过来,所以strcpy,然后拷贝之后释放掉原来的空间

让_str指向tmp所指向的空间,之后更改_capacity的值

代码

	void reserve(size_t n)
	{
		if (n > _capacity)
		{
			char* tmp = new char[n];
			strcpy(tmp, _str);
			delete[]_str;
			_str = tmp;
			_capacity = n;
	}

void insert(size_t pos, char ch)字符前插

错误写法

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

这段代码的逻辑是这样的,让end指向\0位置,从后往前交换
当end==pos的时候,就是将pos位置的字符给pos+1位置,之后pos位置就可以插入我们想要插入的字符了
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
这个写法看上去没什么问题,事实上当pos=0的时候end是不可能小于0的,所以问题就出在这里,因为end是size_t的类型,那我们改成int类型是不是就可以解决了呢?

事实上还是不行,因为pos的类型是size_t,当运算符两边操作数类型不同的时候是会发生类型提升的,提升原则一般是向范围大的类型提升,所以这里的end还是会变成size_t

将pos改成int的话其实也是可以的,但是因为库里的类型就是size_t,所以我们不建议直接将传参类型改成int,而是在判断的时候强制类型转换

代码

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

其次我们还可以在不改变类型的情况下用另外种写法
我们只需要让end变成size+1,当end-pos的时候就直接跳出来,这样就可以避免end<0这样的情况

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

void insert(size_t pos, const char* str)在指定位置插入字符串

错误写法

void insert(size_t pos, const char* str)
{
	assert(pos <= _size);
	size_t len = sizeof(str);
	if (_size + len > _capacity)
	{
		reserve(_size + len);
	}
	size_t end = _size + len;
	while (end > pos)
	{
		_str[end ] = _str[end - len];
		end--;
	}
	strncpy(_str + pos, str, len);
	_size += len;
}

这个写法有两个问题
第一个是size_t len = sizeof(str)有问题,因为sizeof把\0给算进去了,如果算进去\0的话,strncpy(_str + pos, str, len)会把str的\0也给拷贝进去
第二个是end>pos条件有问题,原本是想将pos位置的数据往后挪到,但是有了这个条件后,pos位置之前的数据也会被挪到后面去
在这里插入图片描述
在这里插入图片描述

所以条件判断应该在end>pos+len和end>=pos+len里面去选,具体选谁我们用下面的图来说明
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
因为pos位置的数据可以往后挪,但是pos位置之前的数据不可以挪,所以end-len<=pos,将len往右移得end<=pos+len
在这里插入图片描述

代码

void insert(size_t pos, const char* str)
{
	assert(pos <= _size);
	size_t len = strlen(str);
	if (_size + len > _capacity)
	{
		reserve(_size + len);
	}
	size_t end = _size + len;
	while (end > pos)
	{
		_str[end ] = _str[end - len];
		end--;
	}
	strncpy(_str + pos, str, len);
	_size += len;
}

void push_back(char ch)字符尾差

void push_back(char ch)是一次插入一个字符,因为字符的大小是固定的,所以我们每次需要扩容的时候只扩2被就足够了

并且我们需要判断_capacity=0的情况,所以用一个三目判断来实现

之后将要插入的字符插入的_str中_size位置,因为插入时会将原来的\0覆盖掉,所以在插入后需要++_size,然后将\0再插入到_size位置

写法一

	void push_back(char ch)
	{
		if (_size == _capacity)
		{
			reserve(_capacity==0?4:2 * _capacity);
		}
		_str[_size] = ch;
		++_size;
		_str[_size] = '\0';
	}

写法二

void push_back(char ch)
		{
			insert(_size, ch);
		}

void append(const char* str)字符串尾差

append 的扩容不像push_back一样每次扩2倍,因为append插入的字符串,字符串我们不确定他一次插入多大,所以要算str的长度

然后用strcpy拷贝
这里也可以用strcat,但是strcat需要遍历一遍,找到\0才开始拷贝,这样就比较麻烦,而strcpy是直接在字符串后面拷贝,所以选择用strcpy

写法一

	void append(const char* str)
	{
		size_t len = strlen(str);
		if (_size + len > _capacity)
		{
			reserve(_size + len);
		}
		strcpy(_str + _size, str);
		_size += len;
}

写法二

void append(const char* str)
		{
			insert(_size, str);
		}

string& operator+=(char ch)字符+=

operator+=其实就是尾差一个数据,然后返回string对象的指针

代码

string& operator+=(char ch)
		{
			push_back(ch);
			return *this;
		}

string& operator+=(const char* str)字符串+=

这两个函数内部差异就是push_back和append

代码

		string& operator+=(const char* str)
		{
			append(str);
			return *this;
		}
评论 20
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值