C++ | string类学习 | string的常见接口使用方式

news2024/10/9 14:20:44

目录

为什么要学习string类?

C语言中的字符串

OOP面向对象编程

两个面试题

标准库中的string类

string类了解

string类的文档介绍

总结

string类的常用接口说明

string类对象的常见构造

string类对象的容量操作

size()和length()

clear()

resize(size_t n)与resize(size_t n,char c)

reserve(size_t res_arg=0)

string类对象的访问及遍历操作

operator[]

begin+end 

rbegin+rend

范围for

string类对象的修改操作

 push_back

​编辑append

​编辑 operator+=

find 

​编辑 注意

string类非成员函数

vs和g++下string结构的说明

vs下string的结构

vs下string的设计理念 

g++下string的结构

常见习题

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

 541. 反转字符串 II

557.翻转字符串III:翻转字符串中的单词

45.字符串相乘 


为什么要学习string类?

C语言中的字符串

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

OOP(Object-oriented programming):面向对象编程。

OOP面向对象编程

OOP面向对象编程是一种编程范式,是以对象为核心来组织和构建程序。

两个面试题

在OJ中,有关于字符串的题目基本均是以string类的形式出现的,而且在常规工作中,基本都是用string类,很少程序员会去使用C库中的字符串操作函数。

标准库中的string类

string类了解

string类的文档介绍

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

总结

  • string是表示字符串的字符串类。
  • 该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作。
  • string在底层实际是:basic_string模板类的别名。
typedef basic_string<char,char_traits,allocator> string;
  • 不能操作多字节或者变长字符的序列。
  • 在使用string类时,必须包含#include头文件以及using namespace std。

string类的常用接口说明

string类对象的常见构造

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 Teststring()
{
	string s1;//构造空的string类对象
	string s2("hello bit");//用c格式字符串构造string类对象s2
	string s3(s2);//拷贝构造s3
	string s4(6, 'd');//string类对象中包含6个‘d’
}

string类对象的容量操作

string类对象的容量操作
函数名称函数含义
size返回字符串有效字符长度
length返回字符串有效字符长度
capacity返回空间总大小
empty检测字符串释放为空串,是返回true,否则返回false
clear清空有效字符
reserve为字符串预留空间
resize将有效字符的个数改为n个,多出的空间用字符c填充
size()和length()
  •  size()和length()方法底层实现原理完全相同,引入size()的原因是为了与其他容器的接口保持一致,一般情况下基本都是用size()。

clear()
  •  clear()只是将string中有效字符清空,不改变底层空间的大小。

resize(size_t n)与resize(size_t n,char c)
  •  resize(size_t n)与resize(size_t n,char c)都是将字符串中有效字符个数改变到n个,不同的是当字符个数增多时,resize(n)用0来填充多出的元素空间,resize(size_t n,char c)是用字符c来填充多出的元素空间,如果将元素个数减少,底层空间总大小不变。

reserve(size_t res_arg=0)
  •  reserve(size_t res_arg=0):为string预留空间,不改变有效元素个数,当reserve的参数小于string的底层空间总大小时,reserve不会改变容量大小。

string类对象的访问及遍历操作

string类对象的访问及遍历操作
函数名称函数含义
operator[]返回pos位置的字符,const string类对象调用
begin+end

begin获取第一个字符的迭代器;

end获取最后一个字符的下一个位置的迭代器;

rbegin+rend

begin获取逆置字符串的第一个字符的迭代器;

end获取逆置字符串的最后一个字符的下一个位置的迭代器;

范围forC++11支持更简洁的范围for的新遍历方式
operator[]

begin+end 

rbegin+rend

范围for

string类对象的修改操作

string类对象的修改操作
函数名称函数含义

push_back

尾插字符
append在字符串后追加一个字符串
operator+=在字符串后面追加一个字符串str
c_str

返回c格式字符串

find+npos从字符串pos位置开始往后找字符c,返回该字符在字符串中的位置
rfind从字符串pos位置开始往前找字符c,返回该字符在字符串中的位置
substr在str中从pos位置开始,截取n个字符,然后将其返回
 push_back
append
 operator+=

find 
 注意
  • 在string尾部追加字符时,s.push_back(c) / s.append(1,c) / s+='c'三种的实现方式差不多,一般情况下string类的+=操作用的比较多,+=操作不仅可以连接单个字符,也可以连接字符串。
  • 对string操作时,如果能大概预估到放多少字符,可以先通过reserve把空间预留好。

string类非成员函数

string类非成员函数
函数名称函数含义
operator+尽量少用,因为传值返回,导致深拷贝效率低
operator>>输入运算符重载
operator<<输出运算符重载
getline获取一行字符串
relational operators大小比较

vs和g++下string结构的说明

注意:下述情况是在32位平台下进行验证的,32位平台下指针占用4个字节。

vs下string的结构

string总共占用28个字节,内部结构稍微复杂一点,有一个union联合体,联合体用来定义string中字符串的存储空间

  • 当字符串长度小于16时,使用内部固定的字符数组来存放;
  • 当字符串长度大于等于16时,从堆上开辟空间
union _Bxty
{ // storage for small buffer or pointer to larger one
 value_type _Buf[_BUF_SIZE];
 pointer _Ptr;
 char _Alias[_BUF_SIZE]; // to permit aliasing
} _Bx;
vs下string的设计理念 

大多数情况下字符串的长度都小于16,那string对象创建好之后,内部已经有了16个字符数组的固定空间,不需要通过堆创建,效率高。

其次:还有一个size_t字段保存字符串长度一个size_t字段保存从堆上开辟空间总的容量

最后:还有一个指针做一些其他事情。

故总共占用16+4+4+4=28个字节。

g++下string的结构

G++下,string是通过写时拷贝实现的,string对象总共占4个字节,内部包含了一个指针,该指针指向一块堆空间,内部包含了如下字段:

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

常见习题

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

#include <iostream>
using namespace std;

int main() 
{
    string str;
    getline(cin,str);
    size_t pos=str.rfind(' ');
    cout<<str.size()-(pos+1)<<endl;

    return 0;
}

 541. 反转字符串 II

class Solution {
public:
    string reverseStr(string s, int k)
    {
        int n = s.size();
        int start = 0;
        int end = n - 1;
        while (start < n)//确保在字符串中的这个范围里面
        {
            //剩余的字符>2K === >  反转前k个
            if (start + 2 * k < n)//一个数+固定数 < 另一个数【一个数<另一个数】【两者之间的距离也大于那个固定数】
            {

                reverse(s.begin() + start, s.begin() + start + k);
                //begin从0开始,加start就是反转起始位置
                //
                start = start += 2 * k;
            }
            //剩余的字符<K === >  全部反转
            else if (start + k > n)//剩余的数小于k
            {
                reverse(s.begin() + start, s.end());
                //全部反转就直接到end
                break;
            }
            //k<剩余的字符<2K === >  反转前k个
            else
            {
                reverse(s.begin() + start, s.begin() + start + k);
                break;
            }
        }
        return s;
    }
};

557.翻转字符串III:翻转字符串中的单词

class Solution {
public:
    string reverseWords(string s)
    {
        int size = s.size();
        int i = 0;
        string ret;
        while (i < size)
        {
            int start = i;
            //start记录的是每一个单词的开始
            //i是每个单词之后遍历找单词之后的空格
            while (i < size && s[i] != ' ')
                //要确保找空格是是在字符串的范围内的
            {
                //如果不是空格就说明这个单词没有完,就一直++
                i++;
                //如果i++之后的i对应的位置是空格,就说明此时找到了空格,这个单词结束了
                //那么就不进入这个循环里面
            }

            //找到一个单词的空格
            //此时开辟的新的string 的pos位置和旧的str的本单词的起始位置是一样的
            //因为空格为分割,一个单词各自进行反转,所以每个单词对应的起始位置是一致的
            for (int p = start; p < i; p++)
                //此时i是找到空格的位置,要确保空格不反转,所以就是小于空格的下标
            {
                //此时可以对新的字符串进行后插
                //后插开始的下标是:start的这个单词到空格下标的前一个下标【也就是旧str的单词的最后一个字符下标】
                //单词的个数【进行后插的次数】第一个字符开始到下空格前一个之间的个数
                ret.push_back(s[start + i - p - 1]);
            }

            //将单词进行插入之后,将最后一个的空格也进行后插在新的字符串里面
            while (i < size && s[i] == ' ')
            {
                ret.push_back(' ');
                i++;
                //本单词反转结束,此时i++,让他去找下一个单词的空格
            }
        }
        return ret;
    }
};

45.字符串相乘 

class Solution {
public:
    string multiply(string num1, string num2)
    {
        //如果两字符都是‘0’,那么相乘的结构也是0
        if (num1 == "0" || num2 == "0")
        {
            return "0";
        }

        string ans;//声明一个ret返回的结果字符串
        int m = num1.size(), n = num2.size();
        //其中m和n是两个字符串的个数
        for (int i = n - 1; i >= 0; i--)
            //i是下标,第二个字符串的下标遍历,从后往前 
            //也就是n个字符,就要进行n次的乘法
        {
            //声明一个临时的字符串curr,记录每次乘出来的值
            string curr;
            int add = 0;
            //目前进位为0
            //j的起始位置与i的下标一致,但是j>i,所以此时是插入了cur 插入了比第二个字符串个数少一个的0
            for (int j = n - 1; j > i; j--)
                //此时是为了保证在之后第n次相乘的时候,是保证进位一致
            {
                curr.push_back(0);
            }

            //y是第二个字符此时倒数第i个数字字符-‘0’=数字的值
            int y = num2.at(i) - '0';
            for (int j = m - 1; j >= 0; j--)
                //此时m是第一个字符的个数,也就是要这个多位数要和一位数乘以几遍
            {
                //x是第一个字符,每一次和不同的字符相乘,都要重新从右向左进行遍历
                int x = num1.at(j) - '0';
                //此时第一个字符串的倒数第一个值与第二个字符串的值相乘之后的值为product
                //除此之外还要加上上一次相乘之后遗留下来的进数
                int product = x * y + add;
                //此时在这个结果临时的字符串中后插了product的值的个位数,且保留进数,以便下一趟的使用
                curr.push_back(product % 10);
                //此时进制为add
                add = product / 10;
            }
            //此时第二个字符已经遍历与第一个字符串的所有数字都已经相乘结束
            //但是此时的进位还是不等于0的,所以,此时就需要再在高位数+上
            while (add != 0)
                //此时进制不为0
            {
                //再向curr的字符串后插进制的余数
                curr.push_back(add % 10);
                //再一次更新进制
                add /= 10;
                //直到进制add==0,相乘结束
            }
            reverse(curr.begin(), curr.end());
            //cur一直是pushback,所以逆置一下
            for (auto& c : curr)
                //此时
            {
                c += '0';//此时将字符串中的数字都转化为字符
            }
            ans = addStrings(ans, curr);
            //此时第一趟相乘之后的结果已经得出,我们就得到了此时的第一个需要加起来的值
            //调用相加上一趟的结果值

        }
        return ans;
    }
    //                  ans             curr
    string addStrings(string& num1, string& num2)
    {
        //此时i是结果值结尾的下标,curr是本堂的结果值的结尾的下标
        int i = num1.size() - 1, j = num2.size() - 1, add = 0;
        //此时的进制为0
        string ans;//结果值ans
        while (i >= 0 || j >= 0 || add != 0)
            //两个字符串相加进行:两个字符串都没有结束,且进位不是0
        {
            //x是结果值下标为i(起始在结尾)对应的数字
            int x = i >= 0 ? num1.at(i) - '0' : 0;
            //y是结果值下标为j(起始在结尾)对应的数字
            int y = j >= 0 ? num2.at(j) - '0' : 0;
            //两个数相加的的个位与个位相加、十位与十位相加、+进位
            int result = x + y + add;
            //此时向结尾值插入相加之后所得出的余数
            ans.push_back(result % 10);
            //重新更新余数
            add = result / 10;
            //两个字符串的遍历下标从右向左
            i--; j--;
        }
        //结果字符串是后插高位,将其逆置
        reverse(ans.begin(), ans.end());
        //就将数字改为字符串
        for (auto& c : ans)
        {
            c += '0';
        }
        //返回相应的值
        return ans;
    }
};

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

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

相关文章

【C语言】【Leetcode】2437. 有效时间的数目

文章目录 题目思路一、枚举思路二、回溯 题目 链接: link 思路一、枚举 这题的可以简单的看成 h1 h2 : m1 m2 的情况&#xff0c;其中 h1 和 h2 有关&#xff0c; m1 和 m2 有关&#xff0c;数目不多可以直接暴力枚举解决 int countTime(char * time) {int countHour 0;i…

SQLite下一代查询规划器(十)

返回&#xff1a;SQLite—系列文章目录 上一篇&#xff1a;SQLite 查询优化器概述&#xff08;九&#xff09; 下一篇&#xff1a;SQLite的架构&#xff08;十一&#xff09; 1. 引言 “查询规划器”的任务是弄清楚 找出完成 SQL 语句的最佳算法或“查询计划”。 从 SQLi…

Markdown介绍

一.Markdown基本介绍&#x1f357; Markdown 是一种轻量级标记语言&#xff0c;用于简单、易读易写的文本格式编写。它设计初衷是让人们能够使用普通文本编辑器编写格式简单的文档&#xff0c;并且可以转换成有效的HTML。Markdown 的语法非常简洁直观&#xff0c;通过使用特定…

BIT-5-动态内存管理(C语言进阶)

本章重点 为什么存在动态内存分配动态内存函数的介绍 mallocfreecallocrealloc常见的动态内存错误几个经典的笔试题柔性数组 1. 为什么存在动态内存分配 我们已经掌握的内存开辟方式有&#xff1a; int val 20;//在栈空间上开辟四个字节 char arr[10] {0};//在栈空间上开辟…

好物视频素材在哪找?视频素材大全app下载

创作优质视频内容不仅仅是一种艺术&#xff0c;也是一种科学&#xff0c;需要对素材的深刻理解和精心挑选。掌握了这些高清无水印视频素材&#xff0c;您就拥有了创作引人入胜视频内容的强大工具。以下是更多精选的视频素材网站&#xff0c;旨在为您的视频项目提供更广阔的视野…

uniapp uni.scss中使用@mixin混入,在文件引入@include 样式不生效 Error: Undefined mixin.(踩坑记录一)

问题&#xff1a; 在uni.scss文件定义mixin 2. 在vue文件引入: 3. 出现报错信息: 4. 问题思考&#xff1a; 是不是需要引入uni.scss &#xff1f; 答案不需要 uni.scss是一个特殊文件&#xff0c;在代码中无需 import 这个文件即可在scss代码中使用这里的样式变量。uni-app的…

算法day30 回溯6

332 重新安排行程 给你一份航线列表 tickets &#xff0c;其中 tickets[i] [fromi, toi] 表示飞机出发和降落的机场地点。请你对该行程进行重新规划排序。 所有这些机票都属于一个从 JFK&#xff08;肯尼迪国际机场&#xff09;出发的先生&#xff0c;所以该行程必须从 JFK …

LoRa物联网行业解决方案 1

1 行业应用 智慧停车 智能抄表 智慧牧场 智能生产 智能物流 智能健康 2 物联网智慧农场项目需求 3 为什么选lora&#xff1f; 4 设计 5 模块性能参数 sx1278 lora扩频无线模块 SEMTECH公司SX1278芯片 LoRa 扩频技术 通信距离10000米 SPI通信接口 mcu选型 硬件平台介绍 …

【Web】2024红明谷CTF初赛个人wp(2/4)

目录 ezphp playground 时间原因只打了2个小时&#xff0c;出了2道&#xff0c;简单记录一下 ezphp 参考文章 PHP filter chains: file read from error-based oracle https://github.com/synacktiv/php_filter_chains_oracle_exploit 用上面的脚本爆出部分源码&#xff…

算法打卡day34|动态规划篇02| Leetcode 62.不同路径、63. 不同路径 II

算法题 Leetcode 62.不同路径 题目链接:62.不同路径 大佬视频讲解&#xff1a;不同路径视频讲解 个人思路 这道题非常经典&#xff0c;课后题也有&#xff0c;思路就是先初始化第一行和第一列的值&#xff0c;然后利用动规把到每一步计算出来&#xff0c;这样到终点就知道其左…

【并发编程系列】使用 CompletableFuture 实现并发任务处理

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

AI结合机器人的入门级仿真环境有哪些?

由于使用真实的机器人开发和测试应用程序既昂贵又费时&#xff0c;因此仿真已成为机器人应用程序开发中越来越重要的部分。在部署到机器人之前在仿真中验证应用程序可以通过尽早发现潜在问题来缩短迭代时间。通过模拟&#xff0c;还可以更轻松地测试在现实世界中可能过于危险的…

优酷动漫顶梁柱!神话大乱炖的修仙番为何火爆?

优酷动漫新晋顶梁柱&#xff0c;实时超160万在追的修仙番长啥样&#xff1f; 由优酷动漫联合玄机科技打造的《师兄啊师兄》俨然成为了国漫界一颗璀璨的新星。自去年开播以来热度口碑双丰收&#xff0c;今年在播的第二季人气更是节节攀升&#xff0c;稳坐优酷动漫榜第一把交椅。…

水果销售(源码+文档)

水果销售管理系统&#xff08;小程序、ios、安卓都可部署&#xff09; 文件包含内容程序简要说明含有功能项目截图客户端添加地址首页商品详细意见反馈待发货商品分类我的代付款我的地址搜索防骗指南资料修改登录注册 后端管理分类管理反馈管理订单管理商品管理用户管理 文件包…

Java23种设计模式

本文主要是对Java中一些常用的设计模式进行讲解 后期会进行不断的更新&#xff0c;欢迎浏览 23种设计模式 创建型模式&#xff0c;共五种&#xff1a;工厂方法模式、抽象工厂模式、建造者模式、原型模式、单例模式。结构型模式&#xff0c;共七种&#xff1a;适配器模式、桥接…

实战篇02:注册接口

实战篇02&#xff1a;注册接口 一、注册 1.1、接口信息 1.1.1 基本信息 请求路径&#xff1a;/user/register 请求方式&#xff1a;POST 接口描述&#xff1a;该接口用于注册新用户 1.1.2 请求参数 请求参数格式&#xff1a;x-www-form-urlencoded 请求参数说明&#xff1…

深入浅出 -- 系统架构之微服务架构

1.1 微服务的架构特征&#xff1a; 单一职责&#xff1a;微服务拆分粒度更小&#xff0c;每一个服务都对应唯一的业务能力&#xff0c;做到单一职责 自治&#xff1a;团队独立、技术独立、数据独立&#xff0c;独立部署和交付 面向服务&#xff1a;服务提供统一标准的接口&…

二维码的生成、下载Java,并返回给前端展示

分析 将生成的二维码图片&#xff0c;以IO流的方式&#xff0c;通过response响应体直接返回给请求方。 第一、不需要落到我们的磁盘&#xff0c;操作在内存中完成&#xff0c;效率比较高。 第二、所有生成二维码的请求&#xff0c;都可以访问这里&#xff0c;前端直接拿img标…

【Django学习笔记(三)】BootStrap介绍

BootStrap介绍 前言正文1、BootStrap 快速了解2、初识BootStrap2.1 下载地址2.2 创建目录2.3 引入BootStrap2.4 使用BootStrap 3、BootStrap 组件&样式3.1 导航条3.2 栅格系统3.3 container3.3.1 container3.3.2 container-fluid 3.4 面板3.5 媒体对象3.6 分页3.7 图标3.7.…

RedHat9中KVM虚拟机的配置与管理

KVM虚拟技术介绍 Linux的KVM&#xff08;Kernel-based Virtual Machine&#xff09;虚拟技术是一种基于Linux内核的虚拟化解决方案。它允许在单个物理服务器上创建和运行多个隔离的虚拟机&#xff0c;每个虚拟机都有自己的操作系统和应用程序&#xff0c;就像运行在独立的物理…