【C++自学笔记】STL—string类详解及自主实现string类

一、什么是string类?

1、C语言中的字符串

C语言中,字符串是以'\0'结尾的一些字符的集合,为了操作方便,C标准库 中提供了一些str系列的库函数,但是这些库函数与字符串是分离开的,不太符合OOP的思想,而且底层空间需要用户自己管理,稍不留神可能还会越界访问。

2、什么是string类?

string类是表示字符串的字符串类,该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作。

string在底层实际是:basic_string模板类的别名,typedef basic_string string;

在使用string类时,必须包含头文件<string>以及using namespace std;

二、string的常用接口

1、string的常用构造

//构建一个空的字符串
string();
//用c-string来构造string类对象
string(const char* s);
//构造一个包含有n个c字符的对象
string(size_t n,char c);
//拷贝构造函数
string(const string& s);
//用s中的前n个字符构造一个新对象
string(const string& s,size_t n);

示例:

#include<string>
using namespace std;
int main(){
    string s1;
    string s2("Hello World!");
    string s3(10,'a');
    string s4(s2);
    string s5(s3,5);
    return 0;
}

==> s1是空字符串;s2->"Hello World";s3->"aaaaaaaaaa";s4->"Hello World";s5->"aaaaa";

2、string类对象的容量操作

//返回字符串的有效字符长度
size_t size() const;
//返回字符串的有效字符长度
size_t length() const;
//返回空间的总大小
size_t capacity() const;
//检测字符串是否为空,为空返回ture,不为空返回false
bool empty() const;
//清空有效字符
void clear();

其中需要注意的地方:

  1. size()和length()两者的用法完全相同,而函数后面的const是通过把类成员函数声明为const   以表明它们不修改类对象;
  2. clear()只是将string中的有效字符清空,并不会改变底层空间的大小;

还有几个修改有效字符个数的操作:

//将有效字符的个数改成n个,多出的空间用字符c填充
void resize(size_t n,char c);
//将有效字符的个数改成n个,多出的空间用\0填充
void resize(size_t n);
//为字符串预留空间
void reserve(size_t res_arg=0);

需要注意的地方:

  1. 前两个的用法是一样的,差别只是在有没有第二个参数,如果有就用第二参数填充多出来的部分,如果没有就用\0填充多出来的部分;
  2. reserve(size_t res_arg=0):为string预留空间,不改变有效元素个数,当reserve的参数小于 string的底层空间总大小时,reserver不会改变容量大小

对于reserve()进行如下测试:

void Test() {
	string s("Hello world");
	cout << s.size() << endl;
	cout << s.capacity() << endl;
	s.reserve(500);
	cout << s.size() << endl;
	cout << s.capacity() << endl;
	s.reserve(50);
	cout << s.size() << endl;
	cout << s.capacity() << endl;
}

3、string的类对象访问操作

//返回pos位置的字符,const string类对象调用
char& operator[](size_t pos);
//返回pos位置的字符,非const string类对象调用
const char& operator[](size_t pos) const;

类似于对数组的下标访问;

4、string类对象的修改操作

1、增加

//在字符串后尾插字符串c
void push_back(char c);
//在字符串后追加一个字符串
string& append(const char* c);
//在字符串后追加字符串str
string& operator+=(const string& str);
//在字符串后追加字符C
string& operator+=(char c);

2、返回C格式字符串

const char* c_str()const;

3、寻找/匹配/删除

//从字符串pos位置开始往后匹配字符C,返回C的位置
size_t find(char c,size_t pos = 0)const;
//从字符串pos位置开始往前匹配字符C,返回C的位置
size_t rfind(char c,size_t pos = npos);
//在str中从pos位置开始,截取n个字符,然后将其返回
string substr(size_t pos = 0,size_t n = nops)const;
//在str中从pos位置开始,删除n个字符
string& erase ( size_t pos = 0, size_t n = npos );

==》小练习:去除url中的域名

void UrlStrTest() {
	string url("http://www.baidu.com/hahah/heheh/121231");
	cout << url << endl;
	size_t start = url.find("://");
	if (start == string::npos) {
		cout << "invalid url" << endl;
		return;
	}
	start += 3;
	size_t finish = url.find('/',start);
	string address = url.substr(start, finish - start);
	cout << "address" << address << endl;
}

三、string类的模拟实现

要自主实现string类其实不是很难,但是在完成拷贝构造函数的时候需要注意,之前我们有总结过,默认的拷贝构造函数都是进行浅拷贝,而在string类中实现拷贝构造则需要进行深拷贝,这是特别需要注意的一点!!!那么什么是深拷贝?什么是浅拷贝??

1、深拷贝和浅拷贝

浅拷贝:也称位拷贝,编译器只是将对象中的值拷贝过来。如果对象中管理资源,最后就会导致多个对象共享同一份资源,当一个对象销毁时这份资源就会被释放掉,而此时另一些对象并不知道,还会对原来的内存空间进行资源操作,会发生访问违规;

深拷贝:给每个对象都独立分配资源,保证多个对象之间不会因为共享资源而造成多次释放,造成程序的崩溃;

所以在完成string类的自主实现时,有以下做法:

class string {
public:
	string(const char* str = ""){
		if (str == nullptr) {
			assert(false);
			return;
		}
		_str = new char[strlen(str) + 1];
		strcpy(_str, str);
	}
	string(const string& s)
		:_str(new char[strlen(s._str) + 1])
	{
		strcpy(_str, s._str);
	}
	~string() {
		if (_str) {
			delete[] _str;
			_str = nullptr;
		}
	}
private:
	char* _str;
};

当然除了拷贝构造函数,还有赋值运算符的重载!!!!

2、自主实现string类

namespace My {  
	class String {
	public:
		//构造
		String(const char* str = "") {
			if (str == nullptr) {
				assert(false);
				return;
			}
			_size = strlen(str);
			_capacity = _size;
			_str = new char[_capacity + 1];
			strcpy(_str,str);
		}
		String(const String& s)
			: _str(new char[s._capacity + 1])
			, _size(s._size)
			, _capacity(s._capacity)
		{	
			strcpy(_str, s._str);
		}
		String& operator=(const String& s) {
			if (this != &s) {
				char* pStr = new char[s._capacity + 1];
				strcpy(pStr, s._str);

				delete[] _str;
				_str = pStr;
				_size = s._size;
				_capacity = s._capacity;
			}
			return *this;
		}
		~String() {
			if (_str) {
				delete[] _str;
				_str = nullptr;
			}
		}
		//Iterators:begin、end
		typedef char* Interators;
		Interators Begin() {
			return _str;
		}
		Interators End() {
			return _str + _size;
		}
		//Capacity:size,length,
		void Reserve(size_t res_arg = 0) {
			if (_capacity >= res_arg)
				return;
			else
				_capacity = res_arg;
		}
		//Modify:operator+=、PushBack、Append、
		void PushBack(char c) {
			if (_size == _capacity)
				Reserve(_capacity * 2);
			_str[_size++] = c;
			_str[_size] = '/0';
		}
		void Append(size_t n,char c) {
			for (size_t i = 0; i < n; ++i) {
				PushBack(c);
			}
		}
		void Append(const char* str) {

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

		}

	private:
		char* _str;
		size_t _capacity;
		size_t _size;
	};
}

还没写完,等有时间会完善的~

发布了79 篇原创文章 · 获赞 28 · 访问量 7782

猜你喜欢

转载自blog.csdn.net/weixin_43753894/article/details/98240041