08 string类的使用

为什么要学习string类

c语言中的字符串

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

标准库的string类

1,字符串是表示字符序列的类
2.标准的字符串类提供了对此类对象的支持,其接口类似于标准字符容器的接口,但添加了专门用于用于操作单字节字符串的设计特性
3.string类是使用char作为它的字符类型,使用它的默认char_traits和分配类型,更多信息,参考basic_string
4.string类是basic_string模板类的一个实例,它使用char来实例化basic_string模板类,并用char_traits和allocator作为basic_string的默认参数
5.注意,这个类独立于所使用的编码来处理字节,如果用来处理多字节或边长字符(UTF-8)的序列,这个类的所有成员(如长度或大小)以及它的迭代器,将它按照字节(而不是实际编码的字节)来操作

总结:
1.string是表示字符串的字符串类
2.该类的接口与常规容器的接口基本相同,再添加了一些专门操作string的常规操作
3.string再底层实际是: basic_string模板类的别名,typedef basic_string<char,char_traits,akkocator> string;
4.不能操作多字节或者变长字符的序列

string有四个版本,分别基于不同的编码,默认utf-8,根据字符第一个二进制是1还是0区分用ascii还是2字节一读,还有utf-16和utf-32,wstring
在这里插入图片描述

string类的常用接口

1.string类对象的构造

constructor函数名称功能说明
string() 重点构造空的类对象,空字符串
string(const char*s) 重点c-string构造string类对象
string(size_t, char c)n个字符c
string(const string& s) 重点拷贝构造函数

在这里插入图片描述

void Teststring()
{string s1; // 构造空的string类对象s1string s2("hello bit"); // 用C格式字符串构造string类对象s2string s3(s2); // 拷贝构造s3
}

2. 容量操作

函数名称功能说明
size 重点返回字符串有效字符长度
length返回字符串有效字符长度
capacity返回空间总大小
empty 重点检测字符串是否为空串
clear 重点清空有效字符
reserve 重点为字符串预留空间
resize 重点将有效字符的个数改成n个,多出的空间用字符c填充
void test2()
{string s1("hello");cout << s1.size() << "\n";cout << s1.length() << "\n";cout << s1.capacity() << "\n";/*s1.clear();cout << s1.size() << "\n";cout << s1.length() << "\n";cout << s1.capacity() << "\n";*//*s1.resize(10);cout << s1 << endl;*//*s1.resize(10, 'd');cout << s1 << endl;*//*s1.resize(3);cout << s1.size() << "\n";cout << s1.length() << "\n";cout << s1.capacity() << "\n";*/s1.reserve(20);cout << s1.size() << "\n";cout << s1.length() << "\n";cout << s1.capacity() << "\n";cout << s1 << endl;
}

注意:
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, char c)用字符c填充空间.注意: resize增多,可能会改变容量大小,减少时,空间大小不变
4.reserve(size_t res_art=0):为string预留空间,不改变有效元素个数,当reserve的参数小于string的底层空间总大小时,不会改变容量大小

3. 访问及遍历操作

函数名称功能说明
operator[] 重点返回pos位置的字符,const string类对象调用
begin+endbegin去第一个字符的迭代器,end取最后一个字符下一个位置的迭代器
rbegin+rendrbegin取最后一个字符的迭代器,rend取第一个字符
范围forc++11支持更简洁的for遍历方式
void test3()
{string s1("hello");//遍历1 下标访问for (size_t i = 0; i < s1.size(); i++){cout << s1[i];}cout << endl;//遍历2 迭代器string::iterator it = s1.begin();//string::const_iterator cit = s1.begin();  //const类型for (; it != s1.end(); it++){cout << *it;}cout << endl;//string::reverse_iterator rit = s1.rbegin();//string::const_reverse_iterator crit = s1.begin();auto it1 = s1.rbegin(); //自动推导迭代器类型while (it1 != s1.rend()){cout << *it1;it1++;}cout << endl;//遍历3 范围forfor (auto c:s1){cout << c ;}cout << endl;}

下标[]访问越界会报错,at访问则会抛异常

4. 修改操作

函数名称功能说明
push_back在字符串后面插入字符
append在字符串后追加一个字符串
operator+= 重点在字符串后追加字符串
c str 重点返回c格式字符串,遇\0结束
find+npos 重点从字符串pos位置开始往后找字符c,返回该字符的位置
rfind从字符串pos位置开始往前找字符c,返回该字符位置
substr在str中从pos位置开始,截取n个字符返回
void test4()
{string s1("hello");s1.push_back('c');s1.append("world");s1 += "ni";printf("%s\n",s1.c_str());int pos = s1.find('o');if (pos != string::npos){cout << "找到"<<pos << endl;}int pos2 = s1.rfind('o');if (pos2 != string::npos){cout << "找到" << pos << endl;}string s2 = s1.substr(pos, 2);cout << s2 << endl;
}

注意:
1.在string尾部追加字符时,pushback/append/+=三种实现方式差不多,一般+=用的比较多,不仅可以连接单个字符,还可以是字符串
2.string操作,如果能够预估到村多少字符,可以先通过reserve把空间预留好
3.insert往中间插入,但不推荐,效率不高
4.删除earse同中间插入,给一个位置,不给数量会将后面的全部删除
5.replace替换字符
6.npos的值是-1,size_t类型会变为int最大值

替换字符串指定字符

//	string s1("hello world i love you");
//	string newStr;
//	size_t num = 0;
//	for (auto ch : s1)
//	{
//		if (ch == ' ')
//			++num;
//	}
//	// 提前开空间,避免repalce时扩容
//	newStr.reserve(s1.size() + 2 * num);
//
//	for (auto ch : s1)
//	{
//		if (ch != ' ')
//			newStr += ch;
//		else
//			newStr += "%20";
//	}

两个swap功能一样,而针对类的交换函数更高效,只需要改变指针
在这里插入图片描述

转换c串用于调用c函数的接口,需要传入c字符串,例如打开文件fopen

substr取字符串指定内容,也可以查找任一字符

void test5()
{//string s1("hello");//size_t pos = s1.find('e');//if (pos != string::npos)//{//	string suffix = s1.substr(pos, s1.size() - pos);//第二个参数可以缺省//	cout << suffix;//}//取网址中间内容域名,xxxx.comstring url = "https://legacy.cplusplus.com/reference/string/string/";size_t pos = url.find("://");if (pos != string::npos){size_t finish = url.find('/',pos + 3);string suffix = url.substr(pos + 3, finish - (pos + 3));//第二个参数可以缺省cout << suffix;}url.find_first_of("abcd"); //找字符串中包含任一字符url.find_last_of("abcd"); //倒着找
}

非成员函数

函数名称功能说明
operator+尽量少用,传值返回导致深拷贝效率低
operator>> 重点输入运算符重载
operator<< 重点输出运算符重载
getline 重点获取一行字符串
relational operators大小比较

6. msvc和g++string结构

下述结构式32位平台验证,32位平台指针占4字节

vs的string
共占28字节,内部先有一个联合体,定义string字符串的存储空间

  • 当字符串长度小于16时,使用内部固定的字符数组存放
  • 当字符串长度大于等于16时,从堆上开辟空间
  • 扩容时除第一次外都是1.5被扩容
union _Bxty
{ // storage for small buffer or pointer to larger onevalue_type _Buf[_BUF_SIZE];pointer _Ptr;char _Alias[_BUF_SIZE]; // to permit aliasing
} _Bx;

大多数情况下字符串的长度小于16,string对象创建时需要的空间是固定空间,不用从堆申请,效率高
还有一个size_t保存字符串长度,一个size_t字段保存从对数开辟空间的总量
还有一个指针做其他事情

所以总共28个字节
在这里插入图片描述

*g++结构
string通过写时拷贝实现,string对象共4个字节,内部包含一个指针,指向一块堆空间,包含如下字段:
空间不够2倍扩容

  • 空间总大小
  • 字符串有效长度
  • 引用计数
struct _Rep_base
{size_type _M_length;size_type _M_capacity;_Atomic_word _M_refcount;
};
  • 指向堆空间的指针,保存指针大小

练习

仅仅反转字母
https://leetcode.cn/problems/reverse-only-letters/submissions/
在这里插入图片描述

思路:
用两个下标,一个从头,一个从尾,找到是字母的就交换。交换完记得移动下标,不然还是换这两个

class Solution {
public:string reverseOnlyLetters(string s) {int begin = 0;int end = s.size() - 1;while (begin < end){while (begin < end && !isalpha(s[begin])){begin++;}while (begin < end && !isalpha(s[end])){end--;}swap(s[begin], s[end]);//交换后继续移动一步,防止再次交换begin++;end--;}return s;}
};

找出第一个只出现一次的字母
https://www.nowcoder.com/practice/e896d0f82f1246a3aa7b232ce38029d4?tpId=37&&tqId=21282&rp=1&ru=/activity/oj&qru=/ta/huawei/question-ranking

在这里插入图片描述

思路:
可以利用计数排序的思路,记录字符串内26个字母的数量,然后根据字符串每个字母查看计数,如果是1打印这个字符,如果不是就打印-1

#include <iostream>
using namespace std;int main() {string s;cin >> s;int ary[26] = {0};//计数,对应26个字母for (auto ch : s ) {ary[ch - 'a']++;}for (int  i = 0; i < s.size(); i++) {if (ary[s[i] - 'a'] == 1) {cout << s[i];return 0;}}cout << -1;
}

字符串最后一个单词长度
https://www.nowcoder.com/practice/8c949ea5f36f422594b306a2300315da?tpId=37&&tqId=21224&rp=5&ru=/activity/oj&qru=/ta/huawei/question-ranking

在这里插入图片描述

思路:
记录长度,下标从最后一个字母开始,如果不是空格就循环,统计完长度

也可以利用字符串倒着查找函数,找到第一个空格,用字符串长度减去找到的位置再减1就是最后一个单词的长度

#include <iostream>
using namespace std;int main() {string s;getline(cin, s);//记录下标和长度int length = 0;int sign = s.size() - 1;while (sign >=0 && s[sign] != ' '){length++;sign--;}cout<<length;
}
#include <iostream>
using namespace std;int main() {string s;getline(cin, s);//查找int pos = s.rfind(' ');if(pos != string::npos){cout<<s.size() - pos -1<<endl;}else {cout<<s.size()<<endl;}}

字符串相加
https://leetcode.cn/problems/add-strings/description/

在这里插入图片描述

思路:
两个字符串从最后一位开始,逐个相加,用一个新字符串保存结果。相加得到的数%10后得到存储的数,尾插到新字符串里。/10后得到进位,如果有进位,加到下一个位计算。哪个字符串空了,返回0来相加

注意相加时需要转换为整数,不是字符串ascii相加。最后有进位处理一次。将结果逆置

class Solution {
public:string addStrings(string num1, string num2) {int length1 = num1.size() - 1;int length2 = num2.size() - 1;string s;//预先开辟空间,节省消耗s.reserve( num1.size() >  num2.size()?  num1.size() + 1:num2.size() + 1);int carry = 0;while (length1 >= 0 || length2 >= 0) {//取需要相加的数int val1 = length1 >=0 ? num1[length1] - '0' : 0;int val2 = length2 >=0 ? num2[length2] - '0' : 0;//相加,包括进位int num = val1 +val2 +carry;char ret = num % 10 + '0';s += ret;carry = num / 10;length1--;length2--;}if (carry){s += '1';}reverse(s.begin(), s.end());cout << s;return s;}
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/2812623.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

Laravel04 eloquent

eloquent 1. eloquent2. 创建eloquent model 以及 取数据 1. eloquent 文档地址&#xff1a; https://learnku.com/docs/laravel/8.x/eloquent/9406 下面是我们&#xff0c;通过laravel的DB类从数据库中获取了post记录&#xff0c;那么有没有可能我们直接获取一个post对象&am…

Ansible group模块 该模块主要用于添加或删除组。

目录 创建组验证删除组验证删除一个不存在的组 常用的选项如下&#xff1a; gid  #设置组的GID号 name  #指定组的名称 state  #指定组的状态&#xff0c;默认为创建&#xff0c;设置值为absent为删除 system  #设置值为yes&#xff0c;表示创建为系统组 创建组 ansib…

Netty权威指南——基础篇2(NIO编程)备份

1 概述 与Socket类和ServerSocket&#xff0c;NIO也提供了SocketChannel和ServerSocketChannel两种不同的套接字通道实现。这两种新增的通道都支持阻塞和非阻塞两种模式。阻塞模式使用简单&#xff0c;但性能和可靠性都不好&#xff0c;非阻塞模式则正好相反。一般来说&#xf…

电机效率MAP图

直接使用contourf&#xff0c;需要有[X,Y] meshgrid(x,y), 并用Zf(X,Y)来生成Z轴。但是如果一开始Z轴坐标就不是x,y用函数生成的&#xff0c;而是有个默认的测试数据&#xff0c;又该如何用来画MAP图呢? clc;clear;clf; data_ECO []; //具体数值可以自己填&#xff0c;此处…

240Hz高刷电竞显示器 - HKC VG253KM

&#x1f389;&#x1f389;&#x1f389; 各位电竞爱好者们&#xff0c;今天给大家带来一款神秘武器&#xff0c;一款能够让你在游戏中大展拳脚的高刷电竞显示器 - HKC VG253KM&#xff01;&#x1f525;&#x1f525;&#x1f525; 这款显示器&#xff0c;哎呀&#xff0c;真…

测试环境搭建整套大数据系统(七:集群搭建kafka(2.13)+flink(1.14)+dinky+hudi)

一&#xff1a;搭建kafka。 1. 三台机器执行以下命令。 cd /opt wget wget https://dlcdn.apache.org/kafka/3.6.1/kafka_2.13-3.6.1.tgz tar zxvf kafka_2.13-3.6.1.tgz cd kafka_2.13-3.6.1/config vim server.properties修改以下俩内容 1.三台机器分别给予各自的broker_id…

第40期 | GPTSecurity周报

GPTSecurity是一个涵盖了前沿学术研究和实践经验分享的社区&#xff0c;集成了生成预训练Transformer&#xff08;GPT&#xff09;、人工智能生成内容&#xff08;AIGC&#xff09;以及大语言模型&#xff08;LLM&#xff09;等安全领域应用的知识。在这里&#xff0c;您可以找…

SpringBoot:Invalid bound statement (not found)的原因和解决方案

&#x1f413; 报错信息&#xff1a; &#xff08;无效绑定声明&#xff09;找不到 解析&#xff1a; 你的mapper实例对象和对应的mapper.xml对象未找到 &#x1f413; 排查&#xff1a; 情况一&#xff1a; 1.排除相对应的mapper实例对象路径是否正确 查看相对应的mapper中…

一个完整的性能测试流程,究竟应该是什么样子的?

下午逛一个测试交流群时&#xff0c;聊起性能测试&#xff0c;然后某位群成员说“会用load runner不就是会做性能测试&#xff1f;” 当时觉得这话有点偏颇&#xff0c;虽然我也是一个性能测试道路上的摸索前进者&#xff0c;但是load runner≠性能测试&#xff0c;或者说&…

vue3自定义实现悬浮固定按钮组件

目录 一、需求描述二、代码解读三、结果展示 一、需求描述 需要5个固定的悬浮圆&#xff0c;居于页面的右侧。鼠标悬浮在圆上面会显示对应的文字提示其中包含返回顶部悬浮圆&#xff0c;当页面滑至底部时出现&#xff0c;点击页面滑到顶部。点击按钮会给出弹窗 二、代码解读…

谷歌最强轻量级开源大模型Gemma:小尺寸可商用,性能超越Llama-2,个人PC就能用

前言 谷歌近日发布了其最新的轻量级、开源AI模型——Gemma&#xff0c;这一举措无疑在AI领域引起了广泛的关注。不同于其他闭源大模型&#xff0c;Gemma的推出标志着谷歌在开放模型领域的重要一步&#xff0c;意图通过开放、共享的方式&#xff0c;加速AI技术的普及和应用。 G…

无法访问云服务器上部署的Docker容器(二)

说明&#xff1a;记录一次使用公网IP 接口地址无法访问阿里云服务接口的问题&#xff1b; 描述 最近&#xff0c;我使用Docker部署了jeecg-boot项目&#xff0c;部署过程都没有问题&#xff0c;也没有错误信息。部署完成后&#xff0c;通过下面的地址访问后端Swagger接口文档…

【踩坑】修复报错 you should not try to import numpy from its source directory

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhang.cn] 报错如下&#xff1a; 修复方法一&#xff1a; pip install pyinstaller5.9 修复方法二&#xff1a; pip install numpy1.24.1

使用vuetify实现全局v-alert消息通知

前排提示&#xff0c;本文为引流文&#xff0c;文章内容不全&#xff0c;更多信息前往&#xff1a;oldmoon.top 查看 简介 使用强大的Vuetify开发前端页面&#xff0c;结果发现官方没有提供简便的全局消息通知组件&#xff08;像Element中的ElMessage那样&#xff09;&#xf…

在SAP HANA中使用OData(二)

通常有两种方式通过OData来暴露SAP HANA中的数据库对象&#xff0c;一是直接使用Database Object&#xff0c;比如前一篇和本篇文章介绍的例子&#xff0c;这种方式针对于数据已经存在于SAP HANA中&#xff0c;在Repository中没有对应的设计时对象(Design-time Object)&#xf…

顺丰科技2024届春季校园招聘常见问题解答及SHL测评题库

顺丰科技2024届春季校园招聘常见问题解答及SHL测评题库 Q&#xff1a;顺丰科技2024届校园招聘面向对象是&#xff1f; A&#xff1a;2024届应届毕业生&#xff0c;毕业时间段为2023年10月1日至2024年9月30日&#xff08;不满足以上毕业时间的同学可以关注顺丰科技社会招聘或…

【深度学习笔记】卷积神经网络——LeNet

卷积神经网络&#xff08;LeNet&#xff09; sec_lenet 通过之前几节&#xff0c;我们学习了构建一个完整卷积神经网络的所需组件。 回想一下&#xff0c;之前我们将softmax回归模型&#xff08; sec_softmax_scratch&#xff09;和多层感知机模型&#xff08; :numref:sec_m…

使用mimikata获取域控权限(无免杀)

一、实验环境 windows 7 ip:192.168.1.3 (域内普通用户&#xff0c;有本地管理员权限&#xff0c;但不知明文密码) windows server 2012 ip:192.168.1.1 &#xff08;DC域控&#xff0c;与server2012管理员密码相同&#xff0c;但不知明文密码&#xff09;二、准备工作 1、使…

一文读懂 Python 值传递和引用传递

文章目录 版本前言形参和实参值传递和引用传递Python 变量存储值语义和引用语义值语义引用语义 探讨 Python 值传递和引用传递不可变&#xff08;immutable&#xff09;类型可变&#xff08;mutable&#xff09;类型案例一案例二 拓展&#xff1a;不可变类型真的不可变&#xf…

基于Java SSM框架实现家庭食谱管理系统项目【项目源码+论文说明】

基于java的SSM框架实现家庭食谱管理系统演示 摘要 本论文主要论述了如何使用JAVA语言开发一个家庭食谱管理系统 &#xff0c;本系统将严格按照软件开发流程进行各个阶段的工作&#xff0c;采用B/S架构&#xff0c;面向对象编程思想进行项目开发。在引言中&#xff0c;作者将论…