C++之————string类

1、 标准库中的string类

1.1 对string类的理解

string类的介绍文档

1.2 auto 和 范围 for

auto 关键字

1、在早期C/C++中auto的含义是:使用auto修饰的变量,是具有自动存储器的局部变量,后来这个不重要了。C++11中,标准委员会变废为宝赋予了auto全新的含义即:auto不再是一个存储类型指示符,而是作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得。
2、用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须加&(重点)
3、当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际只对第一个类型进行推导,然后用推导出来的类型定义其他变量。
4、auto不能作为函数的参数,可以做返回值,但是建议谨慎使用
5、auto不能直接用来声明数组

实现:

#include<iostream>
using namespace std;
int func1()
{
   return 1;
}
//void func2(auto a)//这里的auto关键字不能作为参数出现

//但是可以用auto当作返回值
auto func3()
{
   return 2;
{

int main()
{
  int a=1;
  auto b=a;//auto 会自动推导a的类型
  auto c='a';
  auto d =func1();
  //auto e;//auto定义的类型必须有初始值,否则这里的auto会报错
 //typeid().name()可以打印类型
 cout<<typeid(b).name()<<endl;
 cout<<typeid(c).name()<<endl;
 cout<<typeid(d).name()<<endl;
 int x= 10;
 auto y=&x;
 auto* z=&x;
 auto& m= x;
 cout<<typeid(x).name()<<endl;
  cout<<typeid(y).name()<<endl;
   cout<<typeid(z).name()<<endl;
   
 auto aa=1,bb=2;//这是被允许的他们类型一致
 auto cc=3,dd='a'; 编译报错:error C3538: 在声明符列表中,“auto”必须始终推导为同一类型
 
 auto array[]={3,4,4,5};// 编译报错:error C3318: “auto []”: 数组不能具有其中包含“auto”的元素类型
}


在这里插入图片描述
auto的实战效果

#include<iostream>
#include<strinig>
#include<map>
using namespace std;
int main()
{
  std:: map<std::string,std::string> dict= { { "apple", "苹果" },{ "orange",
"橙子" }, {"pear","梨"} };
//std::map<std::string,std::string>::iterator it =dict.begin();
//这里的iterator是map的迭代器,it前面是类型,那么这时我们就可以用auto来代替他
auto it = dict.begin();
while (it != dict.end())
{
cout << it->first << ":" << it->second << endl;
++it;
}
}

但是为此牺牲了一定的可读性!!!!
在这里插入图片描述

范围 for

1、对于一个有范围的集合而言,由程序员来说明循环的范围是多余的,有时候还会容易犯错误。因此C++11中引入了基于范围的for循环。for循环后的括号由冒号“ :”分为两部分:第一部分是范围内用于迭代的变量,第二部分则表示被迭代的范围,自动迭代,自动取数据,自动判断结束。 (范围for的格式)
2、范围for可以作用到数组和容器对象上进行遍历(作用)
3、范围for的底层很简单,容器遍历实际就是替换为迭代器,这个从汇编层也可以看到。(介绍)

#include<iostream>
#include <string>
#include <map>
using namespace std;
int main()
{
int array[] = { 1, 2, 3, 4, 5 };
// C++98的遍历
for (int i = 0; i < sizeof(array) / sizeof(array[0]); ++i)//下标访问
{
array[i] *= 2;
}
for (int i = 0; i < sizeof(array) / sizeof(array[0]); ++i)
{
cout << array[i] << endl;
}
// C++11的遍历
for (auto& e : array)//范围for访问(引用)类型
e *= 2;
for (auto e : array)
cout << e << " " << endl;

string str("hello world");
for (auto ch : str)//普通范围for
{
cout << ch << " ";
}
cout << endl;
return 0;
}

在这里插入图片描述
在这里插入图片描述

1.3string类的常用接口说明

56717519cffee.png)

  1. string类对象的常见构造
(constructor)函数名称功能说明
string()(常用)构造空的string类对象,即空字符串
string(const char* s) (常用)用C-string来构造string类对象
string(size_t n, char c)string类对象中包含n个字符c
string(const string&s) (重点)拷贝构造函数
void test1()
{
strnig s1;//造空的string类对象,即空字符串
string s2("hello world");//用C-string来构造string类对象
stirng s3(s2);//|拷贝构造函数

{

底层:
sting()、string(cons char* s)、string(const string&s)

class string
{
    public:
     string()
    :_str(nullptr)
    ,_size(0);
    ,_capacity(0);
    {}
    string(const char* s)
    {
     _size=strlen(s);
     _size=_capacity;
     _str=new char[strlen(s)+1];
     strcpy(_str,s);   
    }
 string(const string&s)
{ 
 _str=new char[s.capacity+1];
 _size=s._size;
 _capacity=s._capacity;
 strcpy(_str,s._str);
}    
    private:
    char* _str;
   size_t _size;
    size_t _capacity;


}

运用:
在这里插入图片描述

  1. string类对象常见的容量操作
函数名称功能说明
size(重点)链接: size返回字符串有效字符长度
length 链接: length返回字符串有效字符长度
capacity 链接: capacity返回空间总大小
empty (重点)链接: empty检测字符串释放为空串,是返回true,否则返回false
clear (重点)链接: clear清空有效字符
reserve (重点)链接: reserve为字符串预留空间
resize (重点)链接: resize将有效字符的个数该成n个,多出的空间用字符c填充

链接: 演示代码

size:
在这里插入图片描述
在这里插入图片描述
length:
在这里插入图片描述
capacity:
在这里插入图片描述
empty:
判断是否为空,是返回true,否则返回false
clear:
在这里插入图片描述
清除字符串的有效空间,size变为0,但是capacity还是不变

reverse:
在这里插入图片描述

resize:
在这里插入图片描述

功能进一步诠释

  1. size()与length()方法底层实现原理完全相同,引入size()的原因是为了与其他容器的接 口保持一致,一般情况下基本都是用size()。
  2. clear()只是将string中有效字符清空,不改变底层空间大小。
  3. resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不 同的是当字符个数增多时:resize(n)用0来填充多出的元素空间,resize(size_t n, char
    c)用字符c来填充多出的元素空间。注意:resize在改变元素个数时,如果是将元素个数
    增多,可能会改变底层容量的大小,如果是将元素个数减少,底层空间总大小不变。
  4. reserve(size_t res_arg=0):为string预留空间,不改变有效元素个数,当reserve的参 数小于string的底层空间总大小时,reserver不会改变容量大
  1. string类对象常见的访问及遍历操作
函数名称功能说明
operator[] (重点)链接: operator返回pos位置的字符,const string类对象调用
begin+ end 链接: begin+endbegin获取一个字符的迭代器 + end获取最后一个字符下一个位置的迭代器
rbegin + rend链接: rbegin+rendrbegin获取最后一个字符的下一个迭代器 + rend获取第一个字符的迭代器

链接: strig中元素访问及遍历

4.string类对象常见的修改操作

需要注意的是:

  1. 在string尾部追加字符时,s.push_back(c) / s.append(1, c) / s += 'c’三种的实现方式差不多,一般情况下string类的+=操作用的比较多,+=操作不仅可以连接单个字符,还可以连接字符串。
  2. 对string操作时,如果能够大概预估到放多少字符,可以先通过reserve把空间预留
    好。
函数名称功能说明
push_back 链接: push_back在字符串后尾插字符c
append 链接: append在字符串后追加一个字符串
operator+= (重点) 链接: operator+=在字符串后追加字符串
c_str(重点)链接: c_str返回C格式字符串
find链接: find从字符串pos位置开始往后找字符c,返回该字符在字符串中的位置
rfind链接: rfind从字符串pos位置开始往前找字符c,返回该字符在字符串中的位置
substr链接: substr在字符串中pos位置开始,截取n个字符,然后将其返回

链接: strig类对象的修改

push_back:
在这里插入图片描述
append:
在这里插入图片描述

operator+=:
在这里插入图片描述
字符串追加用法与appen、 push_back 差不多

c_str:
在这里插入图片描述

find:
在这里插入图片描述

rfind:
与find类似只不过rfind是从后往前

substr:
在这里插入图片描述
5.string类非成员函数

函数名称功能说明
operator+链接: operator+字符相加(因为是传值返回,避免不了拷贝构造,尽量少用)
operator>>链接: operator>>>>(输入运算符重载)
operator<< 链接: operator<<<<(输出运算符重载)
getline链接: getline获取一行字符串(相比输入运算符重载,getline可以控制结束的符号,可以说比cin更灵活)
relational operators 链接: relational operators大小比较

练习

反转字符串

思路简单:找头和尾在依次交换

class Solution {
public:
bool isLetter(char ch)
{
if(ch >= 'a' && ch <= 'z')
return true;
if(ch >= 'A' && ch <= 'Z')
return true;
return false;
}
string reverseOnlyLetters(string S) {
if(S.empty())
return S;
size_t begin = 0, end = S.size()-1;
while(begin < end)
{
while(begin < end && !isLetter(S[begin]))
++begin;
while(begin < end && !isLetter(S[end]))
--end;
swap(S[begin], S[end]);
++begin;
--end;
}
return S;
}
};

找字符串第一个只出现一个的字符

class Solution {
public:
int firstUniqChar(string s) {
// 统计每个字符出现的次数
int count[256] = {0};
int size = s.size();
for(int i = 0; i < size; ++i)
count[s[i]] += 1;
// 按照字符次序从前往后找只出现一次的字符
for(int i = 0; i < size; ++i)
if(1 == count[s[i]])
return i;
return -1;
}
};

思路:通过数组来确定字符出现的次数,在遍历数组,得出只出现一次的第一次字符

字符串里面最后一个单词的长度

运用到getline来代替cin输入字符串,因为cin>>与scanf类似遇到字符空格(‘ ’)就会结束,而getline则不会
getline(cin,line);最后再用 总数-1-pos=最后一个单词长度

#include<iostream>
#include<string>
using namespace std;
int main()
{
string line;
// while(cin>>line)
while(getline(cin, line))
{
size_t pos = line.rfind(' ');
cout<<line.size()-pos-1<<endl;
}
return 0;
}

string的介绍结束!!!

以下是一个简单的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; } ```
评论 45
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值