string 类中常见操作及其模拟实现

x33g5p2x  于2021-11-22 转载在 其他  
字(11.8k)|赞(0)|评价(0)|浏览(276)

1.string容器的基本概念

本质:string是c++类型的字符串,其本质是一个封装好的类
string和char的区别:
1.char
是一个指针
2.string是一个内部封装了char* 的类,管理这个字符串,是一个char型容器
特点:
string类内部封装了很多成员函数
例如:查找find,拷贝copy,删除delete,替换replace,插入insert
string管理char
所分配的内存,不用担心赋值越界和取值越界等问题,由类内部负责

2.string容器的常用操作string 的构造函数

string();//创建一个空的字符串例如:string str;
string(const string &str)//使用一个string 对象去初始化另外一个string 对象
string(const char*str)//使用字符串s初始化
string (int n,char c)//使用n个字符串c初始化

下面我们来实验

1.string ()

#include<iostream>
using namespace std;
#include<string>
 int main()
{
	string s;
	cout << s;
}

运行结果:

我们可以发现字符串是空的

2.string (const string&str);

#include<iostream>
using namespace std;
int main()
{
	string s = "abvede";
	string s1(s);
	cout << s1;
}

运行结果:

3.string (const char*str);

#include<iostream>
using namespace std;
int main()
{
	string s1("abdedf");
	cout << s1;
}

运行结果:

4.string (int n,char c)

#include<iostream>
using namespace std;
int main()
{
	string s1(3, 'a');
	cout << s1;
}

 3.string 类的基本赋值操作

string &operator=(const char*s)//将char*类型字符串赋值给当前字符串
string &operator=(const string &s)把字符串s赋值给当前字符串
string& operator=(char c)把字符赋值给当前字符串
string &assign (const char*s)把字符串s赋给当前字符串
string &assign(const char*s,int n)把字符串s的前n个字符赋给当前字符串
string &assign(const string&s)把字符串s赋给当前字符串
string &assign(int n,char c)用n个字符赋给当前字符串
string &assign(const string &s,int start,int n)将s从start开始n个字符赋值给字符串

例:string &operator=(const char*s)

#include<iostream>
using namespace std;
int main()
{
	string s = "aveddfhf";
	cout << s << endl;
	return 0;
}

运行结果:

2.string &operator=(const string&s)

#include<iostream>
using namespace std;
int main()
{
	string s = "aveddfhf";
	string s1;
	s1 = s;
	cout << s1<< endl;
	return 0;
}

运行结果:

3.string&operator=(char c);

#include<iostream>
using namespace std;
int main()
{
	string s1;
	s1 = 'a';
	cout << s1 << endl;
	return 0;
}

4.string  &assign(const char*s)

#include<iostream>
using namespace std;
int main()
{
	string s1;
	s1.assign("djfgfjdfgh");
	cout << s1 << endl;
}

运行结果:

string 存取字符字符操作及遍历方法

//string存取字符操作
//char&operator[](int n);通过[]的方式取字符
//char&at(int n);通过at的方式获取字符

例:

#include<iostream>
using namespace std;
int main()
{
	string str = "hello world";
	for (int i = 0; i < str.size(); i++) {
		cout << str[i] << endl;
	}
}

运行结果:

通过at 的方式来获取:

#include<iostream>
using namespace std;
int main()
{
	string str = "hello world";
	for (int i = 0; i < str.size(); i++) {
		cout << str.at(i) << endl;
	}
}

运行结果:

我们可以发现两者的运行结果没有取别,拿这两种方式有什么区别吗?

[]和at的区别:

[]访问越界程序会直接挂掉,而at访问越界会抛出异常out_of_range

#include<iostream>
using namespace std;
int main()
{
	string str = "hello world";
	cout << str[100] << endl;
}

运行结果:


  

我们可以看到此时程序直接崩溃了

通过at的方式来获取:

#include<iostream>
using namespace std;
int main()
{
	string str = "hello world";

	try {
		cout << str.at(100) << endl;
	}
	catch (out_of_range& e) {
		cout << e.what() << endl;
	}

}

运行结果:

string 中如何访问最后一个元素或者第一个元素

访问第一个元素:

1.通过[]

2.通过at

3.通过成员函数的方法 对象.front();

4.通过迭代器

访问最后一个元素与访问第一个元素类似

1.通过[]

2.通过at

3.通过成员函数的方法

4.通过迭代器

例:

#include<iostream>
using namespace std;
int main()
{
	string str = "hello world";
	cout << str[0] << endl;//通过[]
	cout << str.at(0) << endl;//通过at
	cout << str.front() << endl;//通过成员函数
	cout << *str.begin() << endl;//通过迭代器
	return 0;
}

运行结果:

访问最后一个元素:

#include<iostream>
using namespace std;
int main()
{
	string str = "hello world";
	cout << str[str.size() - 1] << endl;
	cout << str.at(str.size() - 1) << endl;
	cout << str.back() << endl;
	cout << *(str.end() - 1) << endl;//注意str.end()返回的是最后一个元素的下一个位置
	return 0;
}

运行结果:

2.string对象的几种遍历方式

1.通过[]或者at加for或者while循环遍历

#include<iostream>
using namespace std;
int main()
{
	string str = "hello world";
	for (int i = 0; i < str.size(); i++) {
		cout << str[i];
	 }
}

运行结果:

2.通过迭代器

#include<iostream>
using namespace std;
int main()
{
	string str = "hello world";
	string::iterator it = str.begin();
	while (it != str.end()) {
		cout << *it;
		it++;
	}
	return 0;
}

运行结果:

3.通过范围for来遍历

#include<iostream>
using namespace std;
int main()
{
	string str = "hello world";
	for (auto& e : str) {
		cout << e;
	}
}

运行结果:

4.通过algorithm里面的for_each来遍历

#include<iostream>
using namespace std;
#include<algorithm>
void myprint(char ch) {
	cout << ch;
}
int main()
{
	string str = "hello world";
	for_each(str.begin(), str.end(), myprint);
}

运行结果:

string 中的拼接操作

/string 类中的拼接操作
//string &operator+=(const char*str)重载+=
//string &operator+=(const string&str)重载+=
//string &operator+=(const char ch)重载+=
//string &append (const char*str)把字符串str连接到当前字符串结尾
//string &append(const char*str,int n)把字符串str前n个字符连接到当前字符串结尾
//string &append(const string&s)和+=一样
//string&append(const string&s int pos,int n)把字符串s中从pos位置开始的n个字符连接到当前字符串
//string &append(int n,char c)在当前字符串结尾添加n个字符c

在这里就不一一测试

string&operator(const char ch)

#include<iostream>
using namespace std;
#include<algorithm>
int main()
{
	string s = "ab";
	s += 'c';
	cout << s << endl;
}

运行结果:

string&operator+=(const char*str)

#include<iostream>
using namespace std;
#include<algorithm>
int main()
{
	string s = "ab";
	s += "abcdeff";
cout<<s<<endl;
}

运行结果:

string &append(const char*str,int n);

#include<iostream>
using namespace std;
#include<algorithm>
int main()
{
	string s = "ab";
	s.append("abcdef", 3);
	cout << s << endl;
}

运行结果:

string&append(int n,char ch);

#include<iostream>
using namespace std;
#include<algorithm>
int main()
{
	string s = "ab";
	s.append(3, '0');
	cout << s << endl;
}

运行结果:

string 中的查找和替换

//int find(const string&str,int pos=0)const查找str第一次出现的位置,默认从0号位置开始找
//int find(const char*s,int pos=0)查找s第一次出现的位置从pos位置开始找
// int find(const char*s,int pos,int n)从pos位置查找s的前n个字符第一次出现的位置
//int find(const char c,int pos=0)查找字符c第一次出现的位置
//int rfind(const string&str,int pos=npos)const查找str最后一次出现的位置,从pos位置开始找
//int rfind(const char*s,int pos=npos)const 查找s最后一次出现的位置,从pos位置开始找
//int rfind(const char*s,int pos,int n)从pos位置开始查找s前n个字符第一次出现的位置
//int rfind(const char ch,int pos=0)const 查找字符ch最后一次出现的位置
//string &replace (int pos,int n,const string&str)替换从pos位置开始n个字符为字符串
//string &replace (int pos,int n,const char*s)替换从pos开始的n个字符为字符串s
#include<iostream>
using namespace std;
#include<algorithm>
int main()
{
	string s1="abcdef";
	string s2 = "abc";
	int ret = s1.find(s2);
	cout << ret;

}

运行结果:

#include<iostream>
using namespace std;
#include<algorithm>
int main()
{
	string s1="abcdef";
	string s2 = "abc";
	int ret = s1.find(s2);
	cout << ret;

}

我们在s1中查找s2中从0号位置开始

运行结果:

int rfind(string&s,int pos=npos);

#include<iostream>
using namespace std;
#include<algorithm>
int main()
{
	string s1="abcdefabc";
	string s2 = "abc";
	int ret = s1.rfind(s2);
	cout << ret;

}

运行结果:

如果没有找到则会返回-1

find和rfind的区别:

find 是从从左往右找,而rfind是从右往左找

string 字串

string substr(int pos=0,int n=npos)const 返回由pos开始的n个字符组成的字符串

#include<iostream>
using namespace std;
#include<algorithm>
int main()
{
	string s1="abcdefabc";
	cout << s1.substr(0, 3);

}

运行结果:

string插入和删除操作

/string&insert(int pos,const char*s)插入字符串
//string&insert(int pos,const string&s)插入字符串
//string&insert(int pos,int n,char c)在指定位置插入n个字符c
//string&erase(int pos,int n=npos)删除从pos开始的n个字符

在这里就不测试了可以自己下来测试一下

string 中的c_str(重点)

string.c_str是Borland封装的String类中的一个函数,它返回当前字符串的首字符地址。

c_str函数的返回值是const char的,不能直接赋值给char,所以就需要我们进行相应的操作转化。
 

#include<iostream>
using namespace std;
#include<algorithm>
int main()
{
	string s = "Chelse";
	const char* str = s.c_str();
	cout << str << endl;
	s[1] = 'm';
	cout << str << endl;

}

运行结果:

第一个输出 当然是 Chelse;
第二个输出呢: Chelse还是Cmelse呢?
答案是Cmelse。
const char的值应该是个常量啊,怎么还能改变值呢?
这就是很多人遇到的坑儿,也许面试的时候你会顺利的回答出来,但是在实际的工程中,往往掉进坑儿里,难以自拔。
const char
, char const*, char* const的区别是什么?老
const char与char const是等价的,指的是指向字符常量的指针,即指针可以改变指向但其指向的内容不可以改变。
而char* const相反,指的是常量指针,即指向不可以改变但指针指向的内容可以改变。因此这里的const char*指向的内容本类是不可以改变的。

那么这里为什么改变了呢?这跟str这个const char的生命周期及string类的实现有关,string的c_str()返回的指针是由string管理的,因此它的生命期是string对象的生命期,而string类的实现实际上封装着一个char的指针,而c_str()直接返回该指针的引用,因此string对象的改变会直接影响已经执行过的c_str()返回的指针引用。

string 模拟实现:

#pragma once 
#include<iostream>
using namespace std;
#include<string.h>
#include<assert.h>
namespace ksy {
	class string
	{
	public:
		typedef char* iterator;
		/*string() :_str(nullptr)
		{}
		string(char*str)
			:_str(str)
		{}*/
		/*string(const char* str = "")
			:_str(new char[strlen(str)+1])
		{
		
			strcpy(_str, str);

		}*/

		/*string&operator=(string& s) {
			if (&s != this) {
				char* tmp = new char[s.size() + 1];
				delete this->_str;
				strcpy(tmp, s._str);
				_str = tmp;
			}
			return *this;
		}*/
		
		void reserve(int n) {
			if (n > _capacity) {
				
				char* newstr = new char[n+1];
				strcpy(newstr, _str);
				delete[]_str;
				_str = newstr;
				_capacity = n;
			}
		}

		void resize(int n,char ch='\0') {
			if (n < _size) {
				_str[n] = '\0';
				_size = n;
			}
			else {
				if (n > _capacity) {
					reserve(n);
				}
				for (int i = _size; i < n; i++) {
					_str[i] = ch;
				}
				_size = n;
				_str[_size] = '\0';

			}

		}
		iterator begin() {
			return _str;
		}
		iterator end() {
			return _str + _size;
		}
		friend ostream& operator<<(ostream& cout, const string& s);
		friend istream& operator>>(istream& cin, string& s);

		string(const  char* str = "") {
			_size = strlen(str);
			_capacity = _size;
			_str = new char[_capacity + 1];//'\0'不是有效字符
			strcpy(_str, str);
		 }
		~string() {
			delete[]_str;
			_str = nullptr;
			_size = _capacity;
	}

		string(const string& s)
			:_str(nullptr)
		{
			string tmp(s._str);
			swap(_str, tmp._str);
	    }
		string& operator=(string s) {
			if (&s != this) {
				swap(_str, s._str);
			}
			return *this;
		}

		size_t size() {
			return _size;
		}

		size_t size()const {
			return _size;
		}

		size_t capacity() {
			return _capacity;
		}
		size_t capacity()const {
			return _capacity;
		}

		char& operator[](int i) {
			assert(i < _size);
			return _str[i];
		}

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

		const char* c_str() {
			return _str;
		}
		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';
		 }

		void append(const char*str) {
			int len = strlen(str);
			if (_size + len > _capacity) {
				reserve(_size + len);
			}
			strcpy(_str + _size, str);
			_size += len;
	  }
		string& operator +=(char ch) {
			this->push_back(ch);
			return *this;
	 }
	
		string& operator+=(const char* str) {
			this->append(str);
			return *this;
	      }
		
		string insert(size_t pos, char ch)
		{
			assert(pos > 0 && pos < _size);
			if (_size == _capacity) {
				size_t newcapacity = _capacity == 0 ? 2 : 2 * _capacity;
				reserve(newcapacity);
			}
			int end = _size;
			while (_size >= pos) {
				_str[end + 1] = _str[end];
				end--;
			}
			_str[pos] = ch;
			_size++;
			return *this;
		}
		string& insert(size_t pos, const char* str)
		{
			assert(pos < _size);
			int len = strlen(str);
			if (len + _size > _capacity) {
				reserve(len + _size);
			} 
			
			int end = _size;
			while (end >= pos) {
				_str[end+len] = _str[end];
				--end;
			}
			strncpy(_str + pos, str, len);
			_size += len;
			return *this;
		}
		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[i - len] = _str[i];
					++i;
				}
				_size -= len;
			}
			return *this;
		}
		size_t  find(char ch, size_t pos = 0)
		{
			for (int i = pos; i < _size; i++) {
				if (_str[i] == ch) {
					return i;
				}
			}
			return npos;
		}

		size_t find(const char* str, size_t pos = 0)
		{
			char*p=strstr(_str, str);
			if (p == nullptr) {
				return npos;
			}
			else {
				return p - _str;
			}

		}
		bool operator<(const string& s)
		{
			int ret= strcmp(_str, s._str);
			return ret < 0;

		}

		bool operator>(const string& s)
		{
			int ret=strcmp(_str, s._str);
			return ret > 0;
		}

		bool operator<=(const string& s)
		{
			return *this < s || *this == s;
		}

		bool operator>=(const string& s)
		{
			return *this > s || *this == s;
		}

		bool operator!=(const string& s)
		{
			return !(*this == s);
		}

		bool operator==(const string& s)
		{
			int ret = strcmp(_str, s._str);
			return ret == 0;
		}

	private:
		char* _str;
		int _size;
		int _capacity;
		static size_t npos;
	};
	size_t string ::npos = -1;

  ostream& operator<<(ostream& cout, const string& s) {
	  for (size_t i = 0; i < s.size(); i++) {
		  cout << s[i];
	  }
	  return cout;
	}
  istream& operator>>(istream& cin, string& s) {
	  
	  while (1) {
		  char ch;
		  ch = cin.get();
		  if (ch == ' ' || ch == '\n') {
			  break;
		  }
		  else {
			  s += ch;
		  }

	  }
	  return cin;
  }

  void test_string() {
	  string s("hfdf");
	 /* cout << s << endl;
	  cout << s.capacity() << " " << s.size();
	  string s1(s);
	  cout << s1 << endl;
	  cout << s1.size() << " " << s1.capacity() << endl;*/
	  for (auto& e : s) {
		  cout << e;
	  }
 }

}

相关文章