STL之string模拟实现

一个问题:C语言中的字符串和C++中的字符串有什么不同?

答:C 语言中:
1、C 语言的字符串实际上是字符数组,C语言的字符串是将很多个字符放在连续的存储空间中,也就是数组。
2、C 语言的字符串是以 ‘\0’ 作为结尾标志的,也就是字符数组以 ‘\0’ 结尾就是 C语言风格的字符串
3、C 语言字符串的 ‘\0’ 结尾标志引发了很多问题:首先,我们很容易遗忘 ‘\0’ 的存在、以及在数据存储时我们要考虑到 ‘\0’、在对 C语言字符串进行操作时,一旦没有 ‘\0’ ,很容易造成缓冲区溢出,从而导致程序崩溃。
C++中:
1、C++ 中引入了自动的内存管理,所以对字符串的拼接、拷贝动作就不用我们考虑申请空间了。在C语言中的strcpy、strcat我们都要考虑字符串的空间是否足够大。
2、C++中的字符串不再使用 ‘\0’ 作为结尾了。
3、如果要获取字符串的长度,C语言中是使用 strlen ,但是 strlen 的时间复杂度是O(n),而 C++中是直接将字符串的长度保存下来了,所以时间复杂度是 O(1);
4、C语言字符串的拷贝是一个一个的拷贝,而C++的字符串拷贝使用的是写时拷贝技术,效率更高。

string模拟实现代码:

#include <iostream>
#include <assert.h>
using namespace std;

class String
{
public:
	typedef char* iterator;
	typedef const char* const_iterator;
	String(char* str = "")
	{
		assert(str != nullptr);
		// _size:有效字符数量,不包含'\0'
		_size = strlen(str);
		_str = new char[_size + 1];
		strcpy(_str, str);		//while(*_str++ = *str++);
		_capacity = _size;
	}

	String(const String& s)
		:_str(nullptr)
		, _size(0)
		, _capacity(0)
	{
		String tmp(s._str);
		Swap(tmp);
	}

	void Swap(String& s)
	{	
		//成员函数swap,完成指针的交换,无深拷贝,效率高
		swap(_str, s._str);
		swap(_size, s._size);
		swap(_capacity, s._capacity);
	}

	String& operator=(String s)
	{
		Swap(s);
		return *this;
	}

	char& operator[](size_t pos)
	{
		assert(pos < _size);
		return _str[pos];
	}

	const char& operator[](size_t pos) const
	{
		assert(pos < _size);
		return _str[pos];
	}

	iterator begin()
	{
		return _str;
	}

	iterator end()
	{
		return _str + _size;
	}

	const_iterator begin() const
	{
		return _str;
	}

	const_iterator end() const
	{
		return _str + _size;
	}

	size_t Size() const
	{
		return _size;
	}

	size_t Capacity() const
	{
		return _capacity;
	}

	~String()
	{
		if (_str)
		{
			delete[] _str;
			_str = nullptr;
			_size = _capacity = 0;
		}
	}

	const char* c_str() const
	{
		return _str;
	}

	void PushBack(char c)
	{
		//检查空间是否足够
		if (_size == _capacity)
		{
			//初始容量设置为15
			size_t newC = (_capacity == 0 ? 15 : 2 * _capacity);
			Reserve(newC);
		}
		_str[_size++] = c;
		_str[_size] = '\0';
	}

	void Reserve(size_t n)
	{
		if (n > _capacity)
		{
			//申请空间
			char* tmp = new char[n + 1];
			strcpy(tmp, _str);
			delete[] _str;
			//更新指针
			_str = tmp;
			//更新容量
			_capacity = n;
		}
	}

	void PopBack()
	{
		if (_size > 0)
		{
			_str[--_size] = '\0';
		}
	}

	void Resize(size_t n, char c = '\0')
	{
		//大于容量,重新分配容量
		if (n > _capacity)
		{
			Reserve(n);
		}
		//大于_size,重新分配_size,多的补'\0'
		if (n > _size)
		{
			memset(_str + _size, c, n - _size);
		}
		_size = n;
		_str[_size] = '\0';
	}

	void Erase(size_t pos, size_t len)
	{
		assert(pos < _size);
		if (pos + len >= _size)
		{
			_size = pos;
			_str[_size] = '\0';
		}
		else{
			//从pos + len的位置开始挪动数据,每个数据向前挪动 len 个位置
			for (size_t i = pos + len; i <= _size; i++)
			{
				_str[pos++] = _str[i];
			}
			_size -= len;
		}
	}

	void Append(const char* str)
	{
		size_t sz = strlen(str);
		if (_size + sz >= _capacity)
		{
			Reserve(_size + sz);
		}
		//从'\0'的位置开始插入字符串str
		strcpy(_str + _size, str);
		_size = _size + sz;
	}

	void Insert(size_t pos, char c)
	{
		assert(pos <= _size);
		//扩容
		if (_size >= _capacity)
		{
			size_t newCapacity = (_capacity == 0 ? 15 : 2 * _capacity);
			Reserve(newCapacity);
		}
		//元素挪动,从后往前挪动,留出pos位置插入新元素
		size_t end = _size;
		//注意此处不要用
		//while (end >= pos){
		//	_str[end + 1] = _str[end];
		//	--end;		
		//因为当头插时,end减到0的时候循环还会进来,然后再减1,由于end是size_t类型,所以会变成整型最大值
		//}
		while (end > pos)
		{
			_str[end] = _str[end - 1];
			--end;
		}
		//插入元素
		_str[pos] = c;
		_size++;
		_str[_size] = '\0';
	}

	void Insert(size_t pos, const char* str)
	{
		assert(pos <= _size);
		size_t sz = strlen(str);
		//增容。因为是插入字符串,所以不能简单的增容二倍,增加的容量要能够放下原有的和新的字符
		if (_size >= _capacity)
		{
			Reserve(_size + sz);
		}

		//挪动元素,从最后一个到最前面,一个一个往后挪
		size_t end = _size + sz;
		while (end > pos + sz - 1)
		{
			_str[end] = _str[end - sz];
			end--;
		}

		//插入新元素,注意不能用strcpy,因为会把新字符串的'\0'也拷贝过去而覆盖原有的数据
		//strncpy可以使用
		strncpy(_str + pos, str, sz);
		//或者一个一个拷贝
		//while(*str)
		//{
		//	  _str[pos++] = *str++;
		//}
		_size += sz;
	}

	size_t find(char c)
	{
		for (size_t i = 0; i < _size; i++)
		{
			if (_str[i] == c){
				return i;
			}
		}
		//如果没找到返回npos
		return npos;
	}
	//静态成员在类外初始化
	static const size_t npos;

	//字符串第一次出现的位置
	size_t find(size_t pos, char* str)
	{
		char* posPtr = strstr(_str + pos, str);
		if (posPtr)
		{
			return posPtr - _str;	//返回坐标
		}
		else
		{
			return npos;
		}
	}

	String& operator+=(char c)
	{
		PushBack(c);
		return *this;
	}

	String& operator+=(const char* str)
	{
		Append(str);
		return *this;
	}

	String& operator+=(const String& s)
	{
		//多种写法
		//1)*this += s._str;
		//2)*this += s.c_str();
		Append(s._str);
		return *this;
	}

private:
	friend ostream& operator<<(ostream& _cout, const String& s);
	char* _str;
	size_t _size;
	size_t _capacity;
};
const size_t String::npos = -1;

ostream& operator<<(ostream& _cout, const String& s)
{
	_cout << s.c_str();
	return _cout;
}

//测试[]
void PrintString(const String& s)
{
	for (size_t i = 0; i < s.Size(); i++)
	{
		cout << s[i];
	}
	cout << endl;
}

//测试iterator
void PrintWithIterator(const String& s)
{
	String::const_iterator sit = s.begin();
	while (sit != s.end())
	{
		cout << *sit << endl;
		++sit;
	}
	cout << endl;
}

void test1()
{
	String s1;
	s1.PushBack('1');
	s1.PushBack('2');
	s1.PushBack('3');
	s1.PushBack('4');
	s1[0] = 'e';
	s1.PopBack();
	s1.Append("asd");
	s1.Resize(3, '\0');
	s1.Reserve(20);
	cout << s1.Capacity() << endl;
	cout << s1.Size() << endl;
	cout << s1.c_str() << endl;
	cout << s1 << endl;
	String s2;
	s2 = s1;
	cout << s2 << endl;
	String s3(s1);
	cout << s3 << endl;
	s3.Erase(2, 1);
	cout << s3 << endl;
	s3.Insert(1, '9');
	cout << s3 << endl;
	s3.Insert(1, "lzl");
	cout << s3 << endl;
	//PrintString(s1);
	//PrintWithIterator(s1);

	cout << s3.find('l') << endl;
	cout << s3.find('w') << endl;
	cout << s3.find(0, "lzl") << endl;
	cout << s3.find(3, "lzl") << endl;

	s3 += 'a';
	cout << s3 << endl;
	s3 += s1;
	cout << s3 << endl;
	s3 += "lzl";
	cout << s3 << endl;
}

int main()
{
	test1();
	system("pause");
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值