c++string类型

概述

string类型是c++的字符串类型,其继承自basic_string类。

使用string需要导入头文件#include <string>,并且在命名空间std下。

c++string是否是写时复制? (像Qt的string一样)?

经过自己的测试,推断,c++的方式不是写时复制,其在赋值的阶段就会开辟新的空间。

 1.  构造string类对象

  •     std::string str1("Hello World");
        std::string str2;

  •     std::string str3(20, '-');                           // str3包含20个中划线
        std::string str4({ "Hello" });                    // 使用初始化列表

  •     std::string str5(str1, 5);                         //  拷贝从str1第5个字符开始后面的字符
        std::cout << str5 << std::endl;              // 输出: World(注意W前面有个空格字符)

  •     const char* str = "Jack";                    
        std::string str6(str, 2);                           // 拷贝str字符串的前两个字符
        std::cout << str6 << std::endl;              // 输出:Ja

2.  string的访问

  •  使用下标
    std::cout << str1[0]    << std::endl;                          // 输出: H  使用下标运算符访问第一                                                                                      个字符,注意越界
    std::cout << str1.at(0) << std::endl;                        // 和下标运算符类似
  • 使用back()和front()
    std::cout << str1.back() << std::endl;                   // 输出d,返回最后一个字符
    str1.back() = 'e';                                                   // 可以通过back()返回修改对应位置                                                                                     字符
    std::cout << str1 << std::endl;                              // Hello Worle

front()的使用方式类似。

  • 使用迭代器   --   其它迭代器的使用和前面容器是类似的

    std::string str1("Hello World");

    for (auto i : str1) {
        std::cout << i << " ";                                      // H e l l o   W o r l d
    }

这是c++11新增的for循环,可以对拥有迭代器的类方便遍历,当然使用迭代器还可以像之前容器那样去遍历(不了解可以去容器章节查看),当然那样写起来比较麻烦。

3. string的长度 

  •      std::string str1("Hello World");
        
        std::cout << str1.length()           << std::endl;     // 11
        std::cout << str1.size()           << std::endl;     // 11
        std::cout << strlen(str1.c_str())  << std::endl;     // 11  

使用strlen需要导入头文件#include  <string.h> 或者 #include <cstring>                                   

注意:                 
c++所有计算字符串长度的函数,计算出的都是字符串的字节数。也就是所如果我们去计算"我爱你"这样的中文字符串的长度,上面的函数都会返回6。因为在程序中一个中文一般占两个字节。

4. c++字符串转化为C语言字符串 

 在使用一些函数的时候,尤其是c的函数,我们需要传入的字符串是C语言的字符串类型:char*,或者是const char*。

这时候我们可以通过c_str()函数将c++字符串转化为C语言字符串。

str.c_str();  其会返回一个const char*的字符串指针。

为什么呢? 

string是c++关于处理字符串封装的一个类,简单来看,其内部就是存在一个char*的指针,然后内部会为它动态开辟空间。并且类中包含了一系列处理字符串的函数。
你使用c_str()它只是将这个指针给你返回回来了。

5. 字符串的容量 

  • std::string str1; 

    str1.reserve(20);                                                    // 开辟20个空间

    std::cout << str1.capacity() << std::endl;               // 打印string目前的容量

容量是指当前字符串对应的空间有多大,它并不等于字符串的长度。

它会根据内部的算法,进行空间的动态扩充,reserve是指定string开辟20个空间,但是实际打印出来并不是,因为它会根据内部的算法进行扩充。(感觉和vector容器是一样的)

6. 字符串的查找 

  • find() 
    此函数可以用来查找string中存放字符串的特定字符和字串,并且可以指定查找位置。
  • 成功找到:   返回找到的第一个字符或者首字符的下标
    没有找到:   返回npos
    如果指定查找的范围超出字符串的范围:  结果未定义
  • std::string str1("Hello World");
    using size = std::string::size_type;             // 给strng内置的类型取一个别名,方便使用

  • size ret = str1.find("He");                            // 查找子串"He",找到返回字段首字符的下                                                                            标,没有找到返回npos
    std::cout << ret << std::endl;

  • size ret1 = str1.find("He", 5);                      // 从下标为5的位置开始查找子串"He"找到返                                                                        回字段首字符的下标,没有找到返回npos

  • size ret2 = str1.find('c');                              // 查找字符c是否存在,存在返回下标找到返                                                                        回字段首字符的下标,没有找到返回npos
    std::cout << ret2 << std::endl;  

  • size ret3 = str1.find("W", 5);                       // 从下标为5的位置开始,查找字符‘w’是                                                                              否存在,找到返回字段首字符的下标,没                                                                          有找到返回npos
     std::cout << ret3 << std::endl;

  • rfind()就是从反方向查找,用法和find()类似

  • find_first_of() 查找第一次出现的子串或者字符

    std::string str1("Hello World");

    str1.find_first_of('H');
    str1.find_first_of('H',6);                          // 从下标为6的位置开始查找
    str1.find_first_of("He",6);                      // 从下标为6的位置开始查找
    str1.find_first_of("He"); 

  • find_last_of() 查找最后一个出现的子串或者字符  --  用法和上面的一样

  • find_first_not_of() 查找第一个出现的与查找子串或者字符不匹配的下标
    size_t ret = str1.find_first_not_of('s');   // 第一个与s不匹配的下标为0

  • find_last_not_off() 和first相反

注意:  1.    如果查找的是子串,那么必须整个串都一样,否则就是不匹配

           2.    后面的四种方法也可以使用npos来判断是否查找成功

6.1 如何判断查找成功和失败

 我们上面说到,查找成功返回对应子串或者字符的首字符下标,查找失败返回npos。npos最开始被定义为-1,但是其并不是一直是-1,所以find()查找失败不一定都返回-1。

看下面代码: 

std::string str1("Hello World");
using size = std::string::size_type;

size ret = str1.find('s');                         // 's'字符在字符串中没有,所以其肯定找不到
if (ret == str1.npos) {                            // 输出:  没有找到
    std::cout << "没有找到" << std::endl;
}
else {
    std::cout << str1[ret] << std::endl;
}

所以判断是否查找失败,我们可以使用其返回值(返回值类型可以是string内置的size_type也可以直接使用size_t)与npos进行比较如果等于npos就是没有找到,找到就返回所在下标。

7. 判断string是否为空

  •  str1.empty();                //  为空返回true,不为空返回false;

8. string的比较 

  •  直接使用比较运算符进行比较   --  比较规则和C语言字符串类似

    std::string str1("Hello World");
    std::string str2("Hello");

    if (str2 < str1) {
        std::cout << "str2小于str1" << std::endl;
    }

  • 使用compare()函数进行比较

    std::string str1("Hello World");
    std::string str2("Hello");


    // str1和str2整体进行比较,相同返回0,str1小返回-1,str1大返回+1
    str1.compare(str2);                  


    // str1下标为[0,5)字符组成的字符串与str2进行比较,返回值和上面一样
    int ret = str1.compare(0,5,str2);    

    // str1下标为[0,5)字符组成的字符串与str2下标为[0,5)的字符组成的字符串进行比较

    int ret2 = str1.compare(0, 5, str2, 0, 4);

注意:  使用compare()可以指定比较两个字符串对应区间内的字符串,但是如果我们指定的区间大于了原来字符串的长度,那么就默认使用字符串的size(),也就是字符串的长度。


举例: 

int ret = str1.compare(0,20,str2);       // 我们这里指定的是str1的[0,20)的字符组成的字符串与str2进行比较,但是我们str1的长度是11,明显20超出了str1的长度,这时候compare()函数就会使用str1.size()也就是str1的长度范围的字符串,也就是[0,11),也就是整个字符串。

9. string的添加 

  • insert()函数

    std::string str1("Hello World");
    std::string str2("编程");
     

    str1.insert(5, "开心");                        // 在下标为5的位置插入"开心"
    str1.insert(0, "美丽");                        // 在下标为0的位置插入"美丽"
    str1.insert(str1.size(), "漂亮");          // 在字符串的尾部添加"漂亮",因为尾部下标就是                                                                字符串的长度

    str1.insert(str1.begin(),'z');               // 在字符串开头的位置插入字符'z'
    str1.insert(str1.end(), 'z');                // 在字符串尾部的位置插入字符'z'

    str1.insert(str1.begin(), 5, 'a');         // 在尾部添加5个a,首部也类似
    str1.insert(0, str2);                          // 在下标为0的位置添加str2

    std::cout << str1 << std::endl;
     

  • 使用append()函数对字符串进行尾部添加
     
    str1.append("123");                    // 尾部添加字符串"123"
     str1.append(str2);                      // 尾部添加字符串str2

  • 直接使用+运算符进行拼接
    str1 += "123";                            // 尾部拼接
    str1 = "123" + str1;                   // 首部拼接
    注意:  使用+直接拼接必须有一个string类对象,不能直接对C语言的字符串进行+,因为那都是地址。

10. string的删除 

  • 使用下标  --  删除对应下标以及之后的所有数据或者相应数量的数据
                        返回值:    返回删除后的string对象

    std::string str1("Hello World");
    std::string str2;

    str2 = str1.erase(2);                                   // 删除下标为2开始的所有字符
    std::cout << str1 << std::endl;
    std::cout << str1 << std::endl;                    // 输出和str1是一样的

    str1.erase(2,3);                                          // 删除从下标为2开始的三个字符,同理也是                                                                       返回删除后的string对象(和上面是一样的)
    std::cout << str1 << std::endl;
     

  • 使用迭代器   --   删除迭代器指向数据,或者迭代器范围的数据
                              返回值:   返回指向删除字符或者字符串的后一个位置字符的迭代器,                                             如果删除的字符后面已经没有字符了,返回end()迭代器(就是                                           指向最后一个元素的下一个位置的迭代器)

    str1.erase(str1.begin());                  // 删除第一个字符,迭代器end()用于删除最后一个
    std::cout << str1 << std::endl;
     

    str1.erase(str1.begin(),str1.begin()+1);     // 删除迭代器范围的字符[beg,end)
    std::cout << str1 << std::endl;

注意:  还是和之前容器所说的一样,使用erase结合循环删除特定元素的时候,应该注意下一个迭代器的位置是erase()的返回值。(具体可以看之前容器部分)

11. string字符串的替换

  •  std::string str1("Hello World");

     std::string str2("Good Good Study");
     

     str1.replace(1, 2, "123");           // 从下标为1的字符开始,共计两个字节替换成"123"
     str1.replace(1, 2, str2);
     std::cout << str1 << std::endl;
     

     str1.replace(str1.begin(), ++str1.begin(), "你好");       // 将迭代器范围[beg,end)内的字                                                                                           符替换成"你好"
    str1.replace(str1.begin(), ++str1.begin(), str2);
    std::cout << str1 << std::endl;
     

    str1.replace(0, 2, str2, 0, 3);            // 将str1从下标为0的字符开始,共计两个字符替换                                                               成str2从下标为0开始,共计3个字符的字符串
    std::cout << str1 << std::endl;
     

    str1.replace(3, 2, "Day Day Up", 2);
    std::cout << str1 << std::endl;            // 将str1下标为3的字符开始,共计两个字符替换成                                                                后面字符串的前2个字符
     

    str1.replace(str1.begin(), ++str1.begin(), "我们", 2);
    std::cout << str1 << std::endl;

  • 返回值:  其返回的就是替换之后的string对象

12. 使用assign()函数进行赋值 

使用方法和前面的方法是类似的,每次使用assign给字符串赋值的时候,都会覆盖原来字符串的值。 

std::string str1;
std::string str2("ch");

str1.assign(5, 'a');               // aaaaa
str1.assign("123");             // 123
str1.assign("123",2);          // 赋值字符串的前两个字符  12
str1.assign(str2);                // ch
str1.assign(str2,1);             // 使用str2下标为1的字符赋值str1  h

13. resize()重新设置字符串长度 

和容器中resize()的用法是类似的。

接收两个参数,第一个参数是一个整数,表示长度变成多少
                         第二个参数是一个字符,用于指定长度变长的时候填充的字符,默认以空格                           填充 

我们通过第一个参数可以指定扩充或者缩短字符串的长度,第二个参数只有扩充长度的时候才有效。

 

std::string str1;
std::string str2("ch");
  
str1.resize(5,'a');
std::cout << str1 << std::endl;    // aaaaa

str2.resize(1);
std::cout << str2 << std::endl;   // c

 14. string类型转换为其它类型

  •  std::stoi();    将字符串转换为int类型
     std::stol();    将字符串转换为long类型
     std::stoll();   将字符串转换为long long类型
  • std::stoul();   将字符串转换为unsigned long类型
    std::stoull();  将字符串转换为unsigned long long类型
  • std::stof();    将字符串转换为float类型
    std::stod();   将字符串转换为double类型
    std::stold();  将字符串转换为long double类型

例子:  用法都类似
 

    std::string str1("123");
    std::cout << std::stoi(str1) << std::endl;     // 123

    std::string str2("123abc");
    std::cout << std::stoi(str2) << std::endl;      // 123

15. to_string() 

返回一个string类型,将别的类型转换为字符串类型。

int a = 5;
std::string str = std::to_string(a); 

16.substr()字符串分割

只是简单的字符串分割。如果要指定分割符分割的话,可以使用前面说的strtok()函数

std::string str("Hello World");

std::string ret = str.substr(0,5);    // 从下标0开始分割5个字符
std::cout << ret << std::endl;        // Hello
std::cout << str << std::endl;        // Hello World

 

注意:  关于string的操作其实都是以字节为准的 (可以跳过)

我们在上面的计算字符串长度,从指定位置查找字符或者子串,删除指定位置的字符,删除指定个数的字符,以及使用replace()替换指定位置的字符,这写都是针对于字节来说的。

指不过上面的操作,都是以英文字符的形式去展示的,英文字符一个字符占用一个字节,所以上面我们都使用字符数表示了,其实不是这样的,实际那些函数操作的是字节。

如果,在例子中使用中文字符(一个字符占两个字节): 

1. 那么计算的长度就是字节数: 字符数*2

2. str1.erase(1);     // 对于中文字符会出现乱码,因为此处的1表示,删除字符串1字节之后的所有字节,中文字符一个占用两个字节,如果你将1字节后面的字节都删除了,表示中文字符的二进制就被截断了,就会出现乱码

str.erase(2);    // 这样表示删除字符串2字节之后的所有字符,对于中文字符,这样才是真正的保留下第一个字符。

3. 对于迭代器也是同理,begin()和end()都是表示一个字节。


4. str1.replace(0, 2, str2, 0, 3);    //  这个取代语句,是将str1第一个位置开始两个字节的元素替换成str2第一个位置开始三个字节的元素。
如果我们操作的是中文,那么替换的字节数必须是2的倍数,否则就会出现乱码。

等等,相关的操作其实都是对于字节数的操作。其实这些你不知道也无所谓,只是如果你去尝试操作放有中文的或者其它多字节字符的字符串的时候,可能会感到蒙。

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

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

相关文章

PingCAP 戴涛:构建面向未来的金融核心系统

作者&#xff1a;戴涛 导读 近日&#xff0c;平凯星辰解决方案技术部总经理戴涛在 2024 数据技术嘉年华活动中&#xff0c;做了主题为“构建面向未来的金融核心系统”的分享&#xff0c;本文为戴涛演讲实录的全文。 文章分析了中国金融行业的发展趋势&#xff0c;并且基于这…

在 Mac OS 上使用 Homebrew 打造便捷的软件安装体验:apt-get install 就是brew install:

标题&#xff1a;在 Mac OS 上使用 Homebrew 打造便捷的软件安装体验 在 Mac OS 系统中&#xff0c;虽然不支持 apt-get install&#xff0c;但我们有幸拥有 Homebrew 这样出色的包管理器。它为我们在 Mac 上安装各种所需软件提供了极大的便利。 一、安装 Homebrew 要安装 Home…

算法提高之加成序列

算法提高之加成序列 核心思想&#xff1a;迭代加深 dfs 从上往下逐渐增大depth 这样下面没有用的方案就不用遍历了 #include <iostream>#include <cstring>#include <algorithm>using namespace std;const int N 110;int n;int path[N];//当前求哪个位置…

PDF编辑阅读器PDF Expert for Mac v3.10.1中文激活版

PDF Expert for Mac是一款易于使用的 PDF 编辑器和注释器&#xff0c;专为 Mac 设备设计。它允许用户轻松查看、编辑、签名、注释和共享 PDF。该软件使用户能够向他们的 PDF 添加文本、图像、链接和形状&#xff0c;突出显示和标记文本&#xff0c;填写表格以及签署数字文档。它…

STL----resize

resize的作用 设置容器元素个数和初始值。 resize和reserve resize即改变容器元素个数&#xff0c;也改变容器容量。 reserve只改变容器容量&#xff0c;不改变容器元素个数。 reserve有什么用 reserve---存储&#xff0c;容量&#xff0c;保留。 1&#xff0c;设置容器容…

Python实现麦克风录音保存到wav

功能展示&#xff1a; 运行环境&#xff1a; Python: 3.10.4 64-bit 操作系统&#xff1a; 截图环境&#xff1a;win10 64-bit 视频录屏环境&#xff1a;win10 64-bit 功能说明&#xff1a; 点击界面开始按钮开始录音&#xff0c;点击停止按钮结束录音。 源码文件列表&…

十二生肖Midjourney绘画大挑战:释放你的创意火花

随着AI艺术逐渐进入大众视野&#xff0c;使用Midjourney绘制十二生肖不仅能够激发我们的想象力&#xff0c;还能让我们与传统文化进行一场新式的对话。在这里&#xff0c;我们会逐一提供给你创意满满的绘画提示词&#xff0c;让你的作品别具一格。而且&#xff0c;我们还精选了…

扫码枪与Input的火花

文章目录 前言一、需求&#xff1a;交互细节二、具体实现两个核心的函数&#xff1a;自动聚焦 三&#xff0c;扩展知识input 与 change的区别 前言 在浏览器扫描条形码获取条形的值&#xff0c;再操作对应的逻辑。这是比较常见的业务&#xff0c;这里记录实际操作。 其中PC端…

2023年国赛高教杯数学建模C题蔬菜类商品的自动定价与补货决策解题全过程文档及程序

2023年国赛高教杯数学建模 C题 蔬菜类商品的自动定价与补货决策 原题再现 在生鲜商超中&#xff0c;一般蔬菜类商品的保鲜期都比较短&#xff0c;且品相随销售时间的增加而变差&#xff0c;大部分品种如当日未售出&#xff0c;隔日就无法再售。因此&#xff0c;商超通常会根据…

JSON 转为json串后出现 “$ref“

问题描述 转为JSON 串时出现 "$ref":"$.RequestParam.list[0]" $ref&#xff1a; fastjson数据重复的部分会用引用代替&#xff0c;当一个对象包含另一个对象时&#xff0c;fastjson就会把该对象解析成引用 “$ref”:”..” 上一级 “$ref”:”” 当前对…

2、架构-服务间的通信

远程服务将计算机程序的工作范围从单机扩展至网络&#xff0c;从本地延 伸至远程&#xff0c;是构建分布式系统的首要基础。而远程服务又不仅仅是为 分布式系统服务的&#xff0c;在网络时代&#xff0c;浏览器、移动设备、桌面应用和服 务端的程序&#xff0c;普遍都有与其他设…

分布式搜索-elaticsearch基础 安装es

这里是在虚拟机的Linux系统里安装es的教程: 1.创建网络 在Finashell终端输入指令 docker network create es-net 2.将es.tar安装包放入tmp的目录下 输入指令加载镜像&#xff1a;docker load -i es.tar 3.再运行docker 命令 docker run -d \--name es \-e "ES_JAVA_O…

UE4_照亮环境_光束light beam

学习笔记&#xff0c;不喜勿喷&#xff0c;侵权立删&#xff01;祝愿生活越来越好&#xff01; 光束&#xff1a;模拟大气中散射的光线。利用定向光源模拟真实曙暮光效果或大气散射的阴影&#xff0c;即可生成 光束 。这些光线为场景添加深度和真实度。 一&#xff1a;一些参数…

RabbitMQ部署指南.md

RabbitMQ部署指南 1.单机部署 我们在Centos7虚拟机中使用Docker来安装。 1.1.下载镜像 方式一&#xff1a;在线拉取 docker pull rabbitmq:3.8-management方式二&#xff1a;从本地加载 在课前资料已经提供了镜像包&#xff1a; 上传到虚拟机中后&#xff0c;使用命令加载…

ASP.NET银行大厅自助信息系统的开发与实现

摘 要 本毕业设计在基于银行业务大厅现有业务的基础上&#xff0c;针对自助银行的概念和其独有特点&#xff0c;通过.NETSQL技术&#xff0c;开发一个简单的银行大厅自助信息系统&#xff0c;完成一些自助银行的业务需求如帐户信息查询、帐户挂失、自助交费、留言、新闻查询…

jmeter中java请求,解决不支持协议和元件,实现自定义元件

目录 java请求 作用场景 JavaTest类源码分析 编写java请求样例 新建java工程&#xff0c;导入jmeter主要依赖。 编写java请求类&#xff0c;继承AbstractJavaSamplerClient, 导入工程为jar包&#xff0c;放置jmeter安装目录下lib/ext目录 重启jmeter&#xff0c;添加ja…

3D,点云下采样

文章目录 一、随机采样1、算法原理2、步骤二、格点采样格点采样的特点三、均匀采样1、类似体素网格采样2、固定间隔采样3、最远点采样四、曲率采样曲率采样的特点:参考资料:对于大规模点云处理而言,直接对点云进行特征提取能较好地保留三维结构信息。但由于点云的无序性,直…

flutter开发实战-log日志存储zip上传,发送钉钉机器人消息

flutter开发实战-log日志存储zip上传&#xff0c;发送钉钉机器人消息 当我们需要Apk上传的时候&#xff0c;我们需要将日志打包并上传到七牛&#xff0c;上传之后通过钉钉通知我们日志下载地址。 这里我使用的是loggy来处理日志 一、引入loggy日志格式插件 在工程的pubspec.…

【经验总结】超算互联网服务器 transformers 加载本地模型

1. 背景 使用 超算互联网 的云服务&#xff0c;不能连接外网&#xff0c;只能把模型下载到本地&#xff0c;再上传上去到云服务。 2. 模型下载 在 模型中 https://huggingface.co/models 找到所需的模型后 点击下载 config.json pytorch_model.bin vocab.txt 3. 上传模型文…

Flutter 中的 CupertinoAlertDialog 小部件:全面指南

Flutter 中的 CupertinoAlertDialog 小部件&#xff1a;全面指南 在Flutter中&#xff0c;CupertinoAlertDialog是用于在iOS风格的应用中显示警告或提示信息的模态对话框。它以其圆角卡片和模糊背景为特点&#xff0c;为用户提供了一个简洁而直观的交互界面。CupertinoAlertDi…