C++———string类

目标:熟悉使用,了解底层原理


一、标准库中的string类

1字符串是表示字符序列的类
2.标准的字符串类提供了对此类对象的支持,其接口类似干标准字符容器的接口,但添加了专门用于操作单字节字符字符串的设计特性。
3.string类是使用char(即作为它的字符类型,使用它的默认char_traits和分配器类型(关于模板的更多信息,请参阅basic_string)。
4.string类是basic string模板类的一个实例,它使用char来实例化basicstring模板类,并用char_traits和allocator作为basic_string的默认参数(关于更多的模板信息请参考basic
string)。
5.注意,这个类独立于所使用的编码来处理字节:如果用来处理多字节或变长字符(如UTF-8)的序列,这个类的所有成员(如长度或大小)以及它的选代器,将仍然按照字节(而不是实际编码的字符)来操作。
总结:
1.string是表示字符串的字符串类
2.该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作。
3.string在底层实际是:basic_string模板类的别名,typedef basic_string<char,char_traits allocatorstring;

1、4个默认成员函数

在这里插入图片描述

#include <string>
void test_string()
{
	string s1;   		 //重点常用     构造
	string s2("hello");  //重点常用     构造
	string s3("hello",2);
	string s4(s2);		 //重点常用     拷贝构造
	string s5(s2,1,2);
	string s6(s2,1,string::npos);
	string s7(s2,1);
	string s8(10,"a");
	
	cout<<s1<<endl;//为空
	cout<<s2<<endl;//hello
	cout<<s3<<endl;//he
	cout<<s4<<endl;//hello
	cout<<s5<<endl;//el 从第一个开始拷贝2个字符
	cout<<s6<<endl;//ello 从第一个开始拷贝到字符的结束
	cout<<s7<<endl;//ello 从第一个开始拷贝到字符的结束 第三个参数默认为string::npos;
	cout<<s8<<endl;//aaaaaaaaaa  拷贝10个a
	s1 = s8;  //重点常用  赋值
	cout<<s1<<endl;//aaaaaaaaaa  拷贝10个a
}

2、string的遍历

在这里插入图片描述

void test_string2()
{
	string s1("hello");
	s1 += ' ';
	s1 += 'world';
	cout << s1 << endl;//hello world
	//遍历每一个字符
	//s1.size()表示字符串的长度
	//读
	for(size_t i = 0;i<s1.size();==i)
	{
		cout << s1[i]<<" ";//h e l l o w o r l d;
	}
	//写
	for(size_t i = 0;i<s1.size();==i)
	{
		s1[i] += 1;
		cout << s1[i]<<" ";//i f m m p ! x p s m e
	}
	//迭代器
	//写
	string::iterator it = s1.begin();
	//áuto it = s1.begin();这种方式也可以
	while(it != s1.end())
	{
		*it  -= 1; // i f m m p ! x p s m e -1后变为 h e l l o w o r l d
		++it;
	}
	cout << endl;
	//读
	it = s1.begin();
	while(it != s1.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;
	//范围for 基于他的范围自动去遍历
	//原理被替换成迭代器   c++11
	for(auto ch :s1)
	{
		cout << ch <<" ";//h e l l o w o r l d;
	}
	//获取字符数组首地址,用C字符串的形式遍历
	const char * str = s1.c_str();
	while(*str)
	{
		cout<< *str << " ";
	}
	cout << endl;
	cout <<  s1 <<endl; //调用的string重载的operator<<
	cout <<  s1.c_str()<<endl; // 直接输出const char*
	return 0;
}

迭代器是一个像指针的东西 begin()返回的是字符串开始的位置 end()返回结束的位置
在这里插入图片描述

3、反向迭代器

在这里插入图片描述

void test_string3()
{
	string s1("hello world")
	//倒着遍历?反向迭代
	string::revesrse_iterator rit = s1.rbegin();
	while(rit != s1.end())
	{
		cout << *rit << " ";//d l r o w o l l e h
		++rit;
	}
}

4、字符串转整型

begin有两种方式接收参数带const和不带const
const 迭代器只能读不能写
在这里插入图片描述

int String2int(const string& str)
{
	int val = 0;
	string::const_iterator it = str.begin();
	while(it != str.end())
	{
		val*=10;
		val+= (*it - '0');
		++it;
	}
	return val;
}
int main()
{
	string nums("12345");	
	cout << String2int(nums)<<endl;
	return 0;
}

5. capacity增容和find查询和substr取子串

capacity
这个容量不一定等于字符串长度。它可以相等或更大,当向字符串中添加新字符时,额外的空间允许对象优化其操作。
请注意,此容量不假定字符串的长度有限制。当这个容量用完并且需要更多时,它会被对象自动扩展(重新分配存储空间)。字符串长度的理论限制由成员max_size给出。
字符串的容量可以在任何时候修改对象,即使这种修改意味着大小的减少或容量尚未耗尽(这与向量容器中的容量保证形成了对比)。
可以通过调用成员保留来显式地更改字符串的容量。
find
在字符串中搜索由其参数指定的序列的第一个匹配项
substr
返回一个新构造的字符串对象,该对象的值初始化为此对象的子字符串的副本

void test_string4()
{
	string s1("hello world")
	cout << s1.capacity()<<endl;//15个字节
	s1+="111111";
	cout << s1.capacity()<<endl;//31个 基本上按照1.5倍去增容
	s1.clear();//删除字符串的内容,该字符串将变为空字符串(长度为0个字符)。
	cout << s1.capacity()<<endl;//删除字符串的内容 capacity的空间不变
	
	size_t pos1 = s1.find('.');//在字符串中搜索由其参数指定的序列的第一个匹配项
	if(pos1 != string::npos)
	{
		cout << s1.substr(pos1) << endl;
}

域名切割

void spliturl (const string& url)
// 分离出url 协议 域名资源名称
//http: www.cplusplus.com/reference/string string rfind
// http://2019ncov.chinacdc.cn/2019-nCoV/
size_t il = url.find(':);
if(il != string::npos)
{
	cout << url.substr(0, i1) << endl;
}
size_t i2 = url.find('/', il + 3);
if(i2 != string::npos)
{
	cout << url.substr(il + 3,i2 -(i1 + 3))<< endl;
}
cout<< urlsubstri + 1) << endl;

6.string中的 reserve()和 resize()

reserve() 为容器预留足够的空间,避免不必要的重复分配。预留空间大于等于字符串的长度。预留空间可以通过capacity()查看。
resize() 调整字符串的大小。如果字符串长度变小,多余的字符会被截掉。若长度变大,可以设置填充的字符。长度可以通过size()查看。

6.1 reserve()

string str = "April";
str.reserve(20);

str的预留空间为15。
在这里插入图片描述
调用函数reserve()后,预留空间变为31。(内存按照(n*16-1)分配)
在这里插入图片描述

6.2 resize()

字符串str的长度变短,多余的字符被裁掉了。也可以增容

string str = "April";
str.resize(3);

在这里插入图片描述
字符串str的长度变长,使用字符 ‘.’填充。(默认填充空字符)

string str = "April";
str.resize(10,'.');

在这里插入图片描述

6.3 string中的插入删除字符

push_back() 将字符追加到字符串的末尾,使其长度增加一。
append() 通过在字符串当前值的末尾附加附加字符来扩展字符串
insert() 字符串中插入其他字符
erase()擦除字符串的一部分,缩短其长度

void test_string5()
{
	string s1("hello world")
	s1.push_back('x');//hello worldx
	s1.append("111111");//hello worldx111111
	
	s1+='x';//hello worldx111111x //推荐用加等
	s1+="1xxxxx";//hello worldx111111x1xxxxx
	
	s1.insert(s1.begin(),'0')//0hello worldx111111x1xxxxx
	s1.erase(1,2);//0hlo worldx111111x1xxxxx
	s1.erase(1);// 0
}

二、模拟实现string类

2.1实现一个简单的string类

//实现一个简单的string类
namespace zh
{
	class string
	{
	public:
		/*string()
			:str(new char[1])
		{
			str[0] = '\0';
		}
		string(char* strs)
			:str(new char[strlen(str)+1])
		{
			strcpy(str, strs) ;
		}*/
		string(char* strs = " ")
			:_str(new char[strlen(strs) + 1])
		{
			strcpy(_str, strs);
		}
		string(const string& s)
			:_str(new char[strlen(s._str)+1])
		{
			strcpy(_str, s._str);
		}
		~string()
		{
			delete[] _str;
			_str = nullptr;
		}

		size_t size() { return strlen(_str); }

		char& operator[](size_t i) { return _str[i]; }

		string& operator = (const string& s)
		{
			if (&s != this)
			{
				//开辟一个和s一样大的空间
				char* pStr = new char[strlen(s._str) + 1];
				strcpy(pStr, s._str);//然后拷贝给当前的
				delete[] _str;//释放旧的空间
				_str = pStr;//然后指向新开的空间
			}
			return *this;
		}
		

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

	};
	void testString1()
	{
		string s0("hello");
		string s1(s0);

		cout << s0.c_str() << endl;
		cout << s1.c_str() << endl;

	}
}
using namespace zh;
int main()
{
	testString1();

	return 0;
}

2.2实现一个支持增删改查的string

//实现一个支持增删改查的string
namespace zh
{
	class string
	{
	public:
		typedef char* iterator;
		iterator begin()
		{
			return _str;
		}
		iterator end()
		{
			return _str + _size;
		}

		string(const char* str ="")
			:_str(new char[strlen(str)+1])
		{
			_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);
			
		}
		void swap(string& s)
		{
			::swap(_str, s._str);
			::swap(_size, s._size);
			::swap(_capacity, s._capacity);
		}
		string& operator=(const string& s)
		{
			this->swap(s);
			return *this;
		}
		~string()
		{
			delete[] _str;
			_str = nullptr;
			_size = _capacity = 0;
		}
		size_t size() const { return _size; }
		size_t capacity() { return _capacity; }
		const char* c_str() { return _str; }
		const char& operator[](size_t i) const { assert(i < _size); return _str[i]; }
		void push_back(char ch)
		{
			/*if (_size == _capacity)
			{
				size_t newcapacity = _capacity == 0 ? 2 : _capacity * 2;
				reverse(newcapacity);
			}
			_str[_size] = ch;
			++_size;
			_str[_size] = '\0';*/
			insert(_size, ch);
		}
		void reverse(size_t n)
		{
			if (n > _capacity)
			{
				char* tmp = new char[n + 1];
				strcpy(tmp, _str);
				delete _str;
				_str = tmp;
				_capacity = n;
			}
		}
		void resize(size_t n,char ch = '\0')
		{
			if (n < _size)
			{
				_str[n] = '\0';
				_size = n;
			}
			else
			{
				if (n > _capacity)
				{
					reverse(n);
				}
				for (size_t i = 0; i < _size; i++)
				{
					_str[i] = ch;
				}
				_size = n;
				_str[_size] = '\0';
			}
		}
		void append(const char* ch)
		{
			/*size_t len = strlen(ch);
			if (_size + len > _capacity)
			{
				reverse(_size + len);
			}
			strcpy(_str+ _size, ch);
			_size += len;*/
			insert(_size, ch);
		}
		string& operator+=(char ch)
		{
			this->push_back(ch);
			return *this;
		}
		string& operator+=(const char* ch)
		{
			this->append(ch);
			return *this;
		}
		string& insert(size_t pos,char ch)
		{
			assert(pos <= _size);
			if (_size == _capacity)
			{
				size_t newcapacity = _capacity == 0 ? 2 : _capacity * 2;
				reverse(newcapacity);
			}
			int end = _size;
			while (end >= pos)
			{
				_str[end + 1] = _str[end];
				--end;
			}
			_str[end + 1] = ch;
			++_size;
			return *this;
		}
		string& insert(size_t pos,const char* ch) 
		{
			assert(pos <= _size);
			//如果空间不够先增容
			size_t len = strlen(ch);
			if (_size + len > _capacity)
			{
				reverse(_size + len);
			}
			//挪动数据
			size_t end = _size;
			while (end >= pos)
			{
				_str[end + len] = _str[end];
				--end;
			}
			/*for (size_t i = 0; i < len; i++)
			{
				_str[pos++] = ch[i++];
			}*/
			strncpy(_str + pos, ch, len);
			_size += len;

			return *this;
		}
		void erase(size_t pos, size_t len = npos)
		{
			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;
			}
		}
		size_t find(char ch, size_t pos =0) 
		{
			for (size_t 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) ;
		}
		bool operator >	 (const string& s)
		{
			return !(*this < s);
		}
		bool operator >=(const string& s)
		{
			return !(*this < s);
		}
		bool operator !=(const string& s)
		{
			return !(*this == s);
		}
	private: 
		char* _str;
		size_t _size;
		size_t _capacity;
		static size_t npos;
	};
size_t string::npos = -1;;
	ostream& operator << (ostream& out, const string& s)
	{
		for (size_t i = 0; i < s.size(); i++)
		{
			cout << s[i];
		}
		return out;
	}
	istream& operator >> (istream& in,  string& s)
	{
		while (1)
		{
			char ch;
			ch = in.get();
			if (ch == ' ' || ch == '\n')
				break;
			else
				s += ch;
		}
		return in;
	}
	void testString()
	{
		string s1("hello");
		
		

	}
}
using namespace zh;
int main()
{
	testString();

	return 0;
}

三、学习语法后做一道简单的算法题

917. 仅仅反转字母 点这里

387. 字符串中的第一个唯一字符 点这里


总结

c++中有很多语法,不知道的可以在这个网站查询:https://cplusplus.com/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
以下是一个简单的C++文字RPG游戏的示例代码,其中包括了基本的角色、战斗和物品系统: ```c++ #include <iostream> #include <string> #include <cstdlib> #include <ctime> using namespace std; // 角色 class Character { public: string name; int hp; int atk; int def; int gold; Character(string n, int h, int a, int d, int g) { name = n; hp = h; atk = a; def = d; gold = g; } // 攻击函数 void attack(Character& other) { int damage = atk - other.def; if (damage < 0) { damage = 0; } other.hp -= damage; cout << name << "攻击了" << other.name << ",造成了" << damage << "点伤害。" << endl; } // 是否死亡 bool isDead() { return hp <= 0; } }; // 物品 class Item { public: string name; int price; int hp; int atk; int def; Item(string n, int p, int h, int a, int d) { name = n; price = p; hp = h; atk = a; def = d; } }; // 商店 class Shop { public: Item items[3]; Shop() { items[0] = Item("草药", 10, 20, 0, 0); items[1] = Item("铁剑", 50, 0, 10, 0); items[2] = Item("铁甲", 100, 0, 0, 10); } // 显示商店物品 void showItems() { cout << "欢迎光临!以下是本店的物品:" << endl; for (int i = 0; i < 3; i++) { cout << i + 1 << ". " << items[i].name << " - " << items[i].price << "金币" << endl; } } // 购买物品 bool buy(Character& c, int choice) { if (c.gold < items[choice - 1].price) { cout << "金币不足,法购买!" << endl; return false; } c.gold -= items[choice - 1].price; c.hp += items[choice - 1].hp; c.atk += items[choice - 1].atk; c.def += items[choice - 1].def; cout << "购买成功!" << endl; return true; } }; // 战斗函数 void battle(Character& player, Character& enemy) { cout << "你遇到了一只" << enemy.name << ",准备战斗!" << endl; while (!player.isDead() && !enemy.isDead()) { player.attack(enemy); if (enemy.isDead()) { cout << enemy.name << "被你打败了!" << endl; player.gold += enemy.gold; return; } enemy.attack(player); if (player.isDead()) { cout << "你被" << enemy.name << "打败了!" << endl; return; } } } int main() { srand(time(NULL)); // 初始化随机数种子 // 初始化角色和商店 Character player("勇者", 100, 10, 5, 50); Character enemies[3] = { Character("史莱姆", 30, 5, 2, 10), Character("骷髅兵", 50, 10, 5, 20), Character("巨龙", 100, 20, 10, 50) }; Shop shop; // 游戏循环 while (true) { cout << "你的状态 - HP:" << player.hp << " ATK:" << player.atk << " DEF:" << player.def << " 金币:" << player.gold << endl; cout << "请选择操作:" << endl; cout << "1. 进入商店" << endl; cout << "2. 进行战斗" << endl; cout << "3. 离开游戏" << endl; int choice; cin >> choice; switch (choice) { case 1: shop.showItems(); cout << "请选择要购买的物品(输入编号):" << endl; cin >> choice; shop.buy(player, choice); break; case 2: battle(player, enemies[rand() % 3]); break; case 3: cout << "游戏结束,欢迎再次光临!" << endl; return 0; default: cout << "无效的操作!" << endl; break; } } return 0; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我中意你呀丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值