【C++學習筆記】----模擬實現string類及成員函數(詳解)

1.簡介

string類是表示字符串的字符類,是一塊連續的空間存儲字符串,並且可以通過統一接口,實現插入,刪除,尾插,查找,迭代器遍歷等一系列操作。

2.代碼展示

#define _CRT_SECURE_NO_WARNINGS 1;
#include<iostream>
#include<assert.h>
using namespace std;
namespace xff {
	class string {
	public:
		typedef char* iterator;
		//迭代器
		iterator begin() {
			return _str;
		}
		iterator rbegin() {	//最後一個字符
			return _str+_size-1;
		}
		iterator end() {
			return _str + _size;
		}
		iterator rend() {	//第一個字符的前一個
			return --_str;
		}
		//構造函數
		string(const char* str=""){
			_size = strlen(str);
			_capacity = _size;
			_str = new char[_capacity + 1];
			strcpy(_str, str);
		}
		//拷貝構造
		string(const string& s)
				:_str(nullptr)
				,_size(0)
				,_capacity(0)
		{
			string tmp(s._str);
			this->swap(tmp);
		}
		//析構函數
		~string(){
			if (_str) {
				delete[] _str;
				_str = nullptr;
				_size = _capacity = 0; 
			}
		}
		//=
		string operator=(string s) {
			this->swap(s);
			return *this;
		}
		//size
		size_t  size()const {
			return _size;
		}
		//capacity
		size_t capacity()const {
			return _capacity;
		}
		//[]
		char& operator[](size_t index) {
			assert(index < _size);
			return _str[index];
		}
		//[]const
		const char& operator[](size_t index)const {
			assert(index < _size);
			return _str[index];
		}
		//c_str
		const char* c_str() {
			return _str;
		}
		void swap( string& s) {
			std::swap(_str, s._str);
			std::swap(_size, s._size);
			std::swap(_capacity, s._capacity);
		}
		//判斷是否爲空
		bool empty() {
			if (_size == 0) {
				return true;
			}
			return false;
		}
		//reserve預留空間
		void reserve(size_t num) {
			if (num > _capacity) {
				char* newstr = new char[num + 1];
				strcpy(newstr, _str);
				delete[] _str;
				_str = newstr;
				_capacity = num;
			}
		}
		//push_back
		void push_back(const char ch) {
			if (_size == _capacity) {
				size_t newcapacity = _capacity == 0 ? 2 : 2*_capacity;
				reserve(newcapacity);
			}
			_str[_size++] = ch;
			_str[_size] = '\0';
		}
		//operator+=()字符
		 string& operator+=(const char ch) {
			this->push_back(ch);
			return *this;
		}
		 //operator+=()字符串
		 string& operator+=(const char* str) {
			this->append(str);
			return *this;
		}
		//append加字符串
		void append(const char* str = "") {
			size_t len = strlen(str);
			if (len + _size > _capacity) {
				/*size_t newcapacity = _capacity = len + _size;
				char* newstr = new char[newcapacity + 1];
				strcpy(newstr, _str);
				delete[] _str;
				_str = newstr;*/
				reserve(len + _size);
			}
			strcpy(_str + _size, str);
			_size += len;
		}
		//將有效字符串置0
		void clear() {
			_size = 0;
		}
		//resize重置有效字符個數
		//小於有效字符個數就截
		//大於補字符
		void resize(size_t num, const char ch ='\0') {
			if (num <= _size) {
				_size = num;
			}
			else {
				while (num - _size > 0) {
					push_back(ch);
				}
			}
		}
		//插入單個字符
		string& insert(size_t pos, const char ch) {
			assert(pos < _size);
			size_t size = _size;
			if (_size == _capacity) {
				size_t newcapacity = _capacity == 0 ? 2 : 2 * _capacity;
				reserve(newcapacity);
			}
			while (pos<=size) 
				{
					_str[size+1] = _str[size];
					--size;
				}
				_str[pos] = ch;
				++_size;	
				return *this;
		}
		//插入字符串
		string& insert(size_t pos, const char* str) {
			assert(pos <= _size);
			size_t len = strlen(str);
			if (_size+len > _capacity) {
				reserve(_size + len);
			}
			int size = _size;
			while ((int)pos <= size)//無符號-1是最大值,容易死循環
			{
				_str[size+len] = _str[size];
				--size;
			}
			strncpy(_str + pos, str, len);//不要複製這個字符串尾部的空格,不然會覆蓋移動的字符
			_size += len;
			return *this;
		}
		//刪除
		//大於等於pos到_size全刪
		//小於保留餘下的,並且移動
		string& erase(size_t pos,size_t len = npos) {
			assert(pos < _size);
			if (len>=_size-pos) {
				_str[pos] = '\0';
				_size = pos;
			}
			else
			{
				size_t i = pos+len;
				while (i <= _size) {
					_str[pos++] = _str[i++];	
				}
				_size -= len;
			}
			return *this;
		}
		//find字符
		size_t find(const char ch, size_t pos = 0) {
			for (size_t i = pos; i < _size; ++i) {
				if (_str[i] == ch) {
					return i;
				}
			}
			return npos;
		}
		//find字符串
		size_t find(const char* str, size_t pos = 0) {
			size_t len = strlen(str);
			size_t dst = pos;
			while (dst<_size) {
				size_t src = 0;
				pos = dst;
				while (src<len&&_str[dst] == str[src]) {
					++src;
					++dst;
				}
				if (src == len) {
					return pos;
				}
				++dst;
			}
			return npos;
		}
		bool operator==(const string& s) {
			int ret = strcmp(_str, s._str);
			if (ret == 0)
				return true;
			return false;
		}
		bool operator!=(const string& s) {
			if (*this == s) {
				return false;
			}
			return true;
		}
		bool operator>(const string& s) {
			int ret = strcmp(_str, s._str);
			if (ret > 0)
				return true;
			return false;
		}
		bool operator<(const string& s) {
			int ret = strcmp(_str, s._str);
			if (ret < 0)
				return true;
			return false;
		}
		bool operator>=(const string& s) {
			if (*this < s) {
				return false;
			}
			return true;
		}
		bool operator<=(const string& s) {
			if (*this > s) {
				return false;
			}
			return true;
		}
		 const string substr(size_t pos, size_t n=npos) {
			assert(pos < _size);
			if (_size-pos<n) {
				n = _size - pos;
			}
			char* newstr = new char[n + 1];
			strncpy(newstr,_str + pos, n);
			newstr[n] = '\0';
			string s(newstr);
			delete[] newstr;
			return s;
		}
	private:
		char* _str;
		size_t _size;
		size_t _capacity;
		const static size_t npos;
	};
	const size_t string::npos = -1;
	//重載<<
	ostream&  operator <<(ostream& _out, const string& s) {
		for (size_t i = 0; i < s.size(); ++i) {
			_out << s[i];
		}
		return _out;
	}
	//重載>>
	istream&  operator >>(istream& _in, string& s) {
		while (1) {
			char ch;
			ch = _in.get();//輸入的全接收,包括空格換行
			if (ch == '\n') {
				break;
			}
			else
			{
				s += ch;
			}
		}	
		return _in;
	}
	void test_String1() {
		string s1;
		//cout << s1 << endl;
		string s2("hello");
		//cout << s2 << endl;
		//cout << s2.size() << "  " << s2.capacity() << endl;
		string s3;
		s3 = s2;
		cout << s3 << endl;
		//cin >> s1;
		//cout << s1 << "  " <<s1.empty()<<endl;
		s2 += "world";
		cout << s2 << endl;
		//迭代器訪問	
		/*string::iterator it = s3.begin();
		while (it != s3.end()) {
			cout << *it << " ";
			++it;
		}
		//for
		for (auto e : s3) {
			cout << e;
		}*/
		//s2.reserve(15);
		//s2.reserve(3);
		//cout << s2 << endl;
		//cout << s2.size() << "  " << s2.capacity() << endl;
		//s3.resize(2);
		//s3.resize(10);
		//cout << s3 << endl;
		//cout << s3.size() << "  " << s3.capacity() << endl;
		//s3.push_back(' ');
		//cout << s3 << " ";
		//cout << s3.size() << "  " << s3.capacity() << endl;
		//s3.append("world!");
		//cout << s3 << " ";
		//cout << s3.size() << "  " << s3.capacity() << endl;
		//s3.insert(0,"a");
		//s3.insert(10, "abc");
		//s3.insert(5,"a");
		//s3.insert(1, 'a');
		//s3.erase(2, 8);
		//s3.erase(0);
		//s3.erase(2, 2);
		//cout << s3 << " ";
		//cout << s3.size() << "  " << s3.capacity() << endl;
		//size_t num1 =s3.find('l');
		//size_t num2 = s2.find("q",1);
		//cout << num1 << " " << num2 << endl;
		//cout << (s3>=s2)<< endl;
		//cout << s3.substr(0, 8);
	}
}


#include<string>
int main() {
	string s1("hello");
	//cout<<s1.substr(2);
	//s1.insert(1,"ac");
	//s1 += " world!";
	//s1.push_back('!');
	//s1.append("world!");
	//s1.reserve(16);
	//s1.resize(14,'a');
	//s1.clear();
	//s1.erase();
	//cout << s1.substr(2);
	//cout << s1 << endl;
	//int num = s1.find("ello",0);
	//cout << s1<<" "<<s1.size()<<" "<<s1.capacity() <<endl;
	/*string::iterator it = s1.begin();
	while (it != s1.end()) {
		cout << *it;
		++it;
		}
	cout << endl;
	string::reverse_iterator rit = s1.rbegin();
	while (rit != s1.rend()) {
		cout << *rit;
		++rit;
	}*/
	xff::test_String1();
	system("pause");
	return 0;
}


3.總結

1.迭代器是c++ STL組件之一,是通用的遍歷容器的方式,講操作和底層實現分離,我們只需要調用對應的接口,就能實現對容器的遍歷,針對不同的數據結構,有規範接口的作用。
2.實現插入刪除等操作時,迭代器會失效,可能會出現重新分配內存空間的情況,迭代器就失效了。
3.clear()清除有效字符,容量不變。
4.reserve(size_t n)預留空間,不改變有效字符個數,擴容作用。
5.resize(size_t n,char ch)改變有效字符個數,小於有效字符個數就只保留到n,大於當前有效字符個數就補ch到n,前面的字符不變。
6.push_back(ch)尾部插入,不可以爲空,可以插空格。
7.append(str) 尾插字符串。
8.erase(pos,n)從pos開始刪除n個字符,默認是最大值size_t npos=-1。
9.insert(_size,str)只能插入字符串,並且小於等於_size。
10.find(str/ch,pos)從pos位置開始查找str/ch,找到返回第一個下標,找不到返回npos,rfind反向查找。
11.c_str() 返回C格式字符串,return _str.
12.substr(pos,n)從pos截取n個字符,默認npos,返回字符串。
13.getline string類的非成員函數,獲取一行字符串,空格也接收,cin會將\n和空格,作爲結束的標誌。
14.reverse(s.begin(),s.end()),結尾是需要逆置的字符的下一個位置。

4.心得體會

通過實現string類,我對string類的認識進一步加強,同時我也更加熟悉構造函數,析構函數等,同時對new,delete的使用更加熟練。初次學習,可能有不對的地方,希望大家指出來,共同進步。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章