" />

欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

STL中的string你了解嗎

 更新時間:2022年03月23日 10:38:57   作者:TangguTae  
這篇文章主要為大家詳細介紹了STL中的string,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助

STL(standard template libaray-標準模板庫):是C++標準庫的重要組成部分,不僅是一個可復用的組件庫,而且是一個包羅數(shù)據(jù)結構與算法的軟件框架。

STL的六大組件:容器、迭代器、適配器、空間配置器、仿函數(shù)、算法。

string的行為與普通容器類似,但是并不能說它是個容器,因為無法接受所有類型的數(shù)據(jù)。

string是表示字符串的字符串類。

string在底層實際是:basic_string模板類的別名

typedef basic_string<char, char_traits, allocator>string;

頭文件: #include<string>

模擬實現(xiàn)一個string類

首先成員變量最少需要一個字符類型的指針、字符串的大小、總共能存多少有效字符。

其次還需要構造函數(shù)、遍歷的方法、增刪查改、運算符重載等。

成員變量

class MyString
{
private:
	char *_str;//字符串指針
	size_t _size;//字符串大小
	size_t _capacity;//總共能存多少有效字符,不包括'\0'
	static size_t npos;//迭代器相關
}
size_t MyString:: npos = -1;

構造函數(shù)

//構造函數(shù)
MyString(const char* str = "")//缺省參數(shù)
{
	_size = strlen(str);//初始化
	_capacity = _size;
	_str = new char[_capacity + 1];//'\0'的空間+1
	strcpy(_str, str);
}
//析構函數(shù)
~MyString()
{
	delete[] _str;//釋放內存
	_str = nullptr;//將指針置空
	_size = 0;//清理工作
	_capacity = 0;
}
//拷貝構造函數(shù)
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類時,通過重載[ ]實現(xiàn)相同的效果。

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的成員函數(shù)和重載,原因:權限擴大了。

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;
}

與容量相關的成員函數(shù)

實現(xiàn)幾個比較常用的函數(shù)接口

//返回字符串大小
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、capacity、empty只需要設置成const類型,因為不需要修改內容。

reserve只修改_capacity的大小。

resize的實現(xiàn)需要分三種情況,當n的長度小于等于_size的時候,只需要修改一下_size的大小,然后把_size的位置設置為'\0'。當n的長度大于_size且小于_capacity的時候,需要新插入n-_size個ch;如果大于_capacity,說明需要重新開辟空間了,并插入n-_size個ch。

運算符的重載

1、+=的重載

平常用string類的時候發(fā)現(xiàn)+=進行字符串拼接很方便。

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函數(shù):遇到'\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位的最大值,成為死循環(huán)
		_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;
}

可以看出刪除和任意位置插入還是挺費時間的,需要整體挪動字符串。

常用的幾個字符串函數(shù)

findsubstr、c_str也得掌握

find的接口比較多,可以查找string類、查找char*的字符串也可以查找單個字符

返回值為對應的下標,沒找到返回npos。

substr獲得一個子串,返回值為string類型

pos表示從哪里開始,len表示子串長度。

c_str 將C++的字符串類轉化成C語言中char*類型。

總結

本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關注腳本之家的更多內容!

相關文章

最新評論