C++中并不提倡继续使用C风格的字符串,而是为字符串定义了专门的类,名为string。

使用前的准备工作

在使用string类型时,需要包含string头文件,且string位于std命名空间内:

#include <iostream>
//...
std::string str1 = "Hello world!";
  • 1
  • 2
  • 3

另外需要注意的是,由于历史原因,C++中的字符串字面值并不是C++中std::string类型的对象,而是沿用了C风格字符串。

string类的构造

string类一共有三类构造方式,我将其简称为“1,2,3”,即1种空串构造方法,2种直接构造方法,3种拷贝构造方法。 
+ 构造一个空串

string str0;
  • 1
  • 直接构造
string str1("Hello world!");
  • 1

在此情况下,调用的是string类的构造函数,传入的是const char*类型,即string::string(const char *),当然,这里给出的函数进行了简化,实际情况下还涉及分配器等细节,自然要复杂一些。

  • 直接构造重复字符的串
string str666(6, '6');
// str666 == "666666"
  • 1
  • 2

这操作我也是从书上看来的,以前根本没用过,估计以后也很少用上。

  • 拷贝构造

    • 用C风格字符串拷贝构造(实现方式值得商榷)
string str2 = "Hello world!";
  • 1

按理说,在这种情况下应该先调用string::string(const char *)构造函数,为右侧字符串创建一个临时的string对象,再调用str2的拷贝构造函数,传入临时对象的引用。但在VS2017中应该是进行了优化,并没有创建临时对象,而是也形成了直接初始化。 
两种情况下对应的反汇编代码如下(VS2017):

   79:  string str1("Hello world!");
00269F34 68 94 DC 26 00 push offset string "Hello world!" (026DC94h)
00269F39 8D 4D CC lea ecx,[str1]
00269F3C E8 04 72 FF FF call std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_string<char,std::char_traits<char>,std::allocator<char> > (0261145h)
00269F41 C7 45 FC 00 00 00 00 mov dword ptr [ebp-4],0
80: string str2 = "Hello world";
00269F48 68 D8 DD 26 00 push offset string "Hello world" (026DDD8h)
00269F4D 8D 4D A8 lea ecx,[str2]
00269F50 E8 F0 71 FF FF call std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_string<char,std::char_traits<char>,std::allocator<char> > (0261145h)
00269F55 C6 45 FC 01 mov byte ptr [ebp-4],1
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 传入其他string对象拷贝构造(方法一)
string str3(str1);
  • 1
  • 传入其他string对象拷贝构造(方法二)
string str4 = str2;
  • 1

上述两种拷贝构造方式在VS2017中都生成了相同的汇编代码(反正都是调用拷贝构造函数,代码当然相同喽)

    81:     string str3(str1);
008B9F59 8D 45 CC lea eax,[str1]
008B9F5C 50 push eax
008B9F5D 8D 4D 84 lea ecx,[str3]
008B9F60 E8 D4 73 FF FF call std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_string<char,std::char_traits<char>,std::allocator<char> > (08B1339h)
008B9F65 C6 45 FC 02 mov byte ptr [ebp-4],2
82: string str4 = str2;
008B9F69 8D 45 A8 lea eax,[str2]
008B9F6C 50 push eax
008B9F6D 8D 8D 60 FF FF FF lea ecx,[str4]
008B9F73 E8 C1 73 FF FF call std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_string<char,std::char_traits<char>,std::allocator<char> > (08B1339h)
008B9F78 C6 45 FC 03 mov byte ptr [ebp-4],3
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

常用操作

输入输出

  • 输出到ostream:<<
  • 接收输入:>>
  • 从输入中取一行:getline(istream, str)

判断

  • str1.empty():判断str1是否为空串,是则返回true
  • str1 + str2:字符串连接,将str2的内容追加到str1后
  • str1 == str2:判等,若str1与str2内容完全相同,则返回true
  • str1 != str2:是上述操作的逆操作
  • <,<=,>,>=:按字典顺序对字符串进行大小写敏感的比较

获取或设置

  • str1.size():返回str1的长度(即字符的个数) 
    注意:为了实现平台无关性,该函数返回类型为string::size_type,这是一个无符号的数,可让支持C++11标准的编译器进行自动类型推导:
auto str1Len = str1.size();
  • 1

同时需要注意的是,由于该函数返回的是无符号数,在比较时,不应将其与带符号数进行比较,否则对于负数由于存储方式与较大的正数相同,会造成bug。 
+ str1[x]:去除str1中下标为n的字符引用(可get到值也可以set值)

对字符的处理

字符处理头文件和常用函数

C++中将C语言标准库文件ctype.h命名为了cctype,其中包含了一些字符类型的判定和修改函数:

遍历string中的字符

方法一——传统for循环

这种方法大家都应该或多或少的使用过。下面是一段使用此方法将字符串中字母都转为大写的代码:

string str1("Hello world!");
for (string::size_type i = 0; i < str1.size(); i++)
{
str1[i] = toupper(str1[i]);
}
  • 1
  • 2
  • 3
  • 4
  • 5

再次提醒,循环变量的类型应该为string::size_type。

方法二——decltype简化类型定义的传统for循环

在上例中,如果觉得手写string::size_type麻烦,而auto又没起到预期效果时,decltype关键字就登场了,其说明i的类型与str1.size()的返回值相同。

string str1("4ever and 4ever");
for (decltype(str1.size()) i = 0; i < str1.size(); i++)
{
str1[i] = toupper(str1[i]);
}
  • 1
  • 2
  • 3
  • 4
  • 5

方法三——基于范围的for循环(range-based for loop)

无需修改字符串

这种for循环是C++11给我们的语法糖,和Java中的增强for循环一个套路,不用白不用。

string str1("4ever and 4ever");
unsigned int digitNum = 0;
for (auto c : str1)
{
if (isdigit(c))
{
digitNum++;
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

方法四——使用迭代器

其实在方法三中基于范围for循环的原理,就是其在底层利用迭代器完成了对字符串序列的遍历。下面,就让我们自己调用迭代器完成同样的工作。

无需修改字符串

对于不需要修改字符串的情况,选择string类的常量迭代器即可。

string str1("4ever and 4ever");
unsigned int digitNum = 0;
for (string::const_iterator itr = str1.begin(); itr != str1.end(); itr++)
{
if (isdigit(*itr))
{
digitNum++;
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

需要修改字符串

在需要修改字符串内容的情况下,需要使用string类的非常量迭代器:

string str1("4ever and 4ever");
for (string::iterator itr = str1.begin(); itr != str1.end(); itr++)
{
*itr = toupper(*itr);
}
  • 1
  • 2
  • 3
  • 4
  • 5

需要修改字符串

将循环变量设置为引用类型即可。还是将字符串中英文字母转为大写的例子,在使用基于范围的for循环后,被简化成了:

string str1("4ever and 4ever");
for (auto& c : str1)
{
c = toupper(c);
}
  • 1
  • 2
  • 3
  • 4
  • 5

最后友情提醒,C++标准中并没有要求标准库检查字符串下标是否合法。一旦下标超出字符串长度范围,并不会向Java一样抛出超出范围,而是将产生越界读写。所以,在进行下标操作时,一定要小心小心再小心!

版权声明:版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/LPWSTR/article/details/77927659

漫话C++之string字符串类的使用(有汇编分析)的更多相关文章

  1. C++自定义String字符串类,支持子串搜索

    C++自定义String字符串类 实现了各种基本操作,包括重载+号实现String的拼接 findSubStr函数,也就是寻找目标串在String中的位置,用到了KMP字符串搜索算法. #includ ...

  2. 17.C++-string字符串类(详解)

    C++字符串string类 在C语言里,字符串是用字符数组来表示的,而对于应用层而言,会经常用到字符串,而继续使用字符数组,就使得效率非常低. 所以在C++标准库里,通过类string从新自定义了字符 ...

  3. Java String 字符串类细节探秘

    一. 字符串基本知识要点 字符串类型String是Java中最常用的引用类型.我们在使用Java字符串的时候,通常会采用两种初始化的方式:1. String str = "Hello Wor ...

  4. String字符串类总结

    object类 int hashCode() Object定义的hashCode方法能为不同对象返回不同的整数.实际上是把JVM给对象分配的地址转化为整数,确保了逻辑上的唯一性.而转化的散列算法,可能 ...

  5. String字符串类的获取功能

    StringDemo.java /* * String类的获取功能: * int length():获取字符串的长度,其实也就是字符个数 * char charAt(int index):获取指定索引 ...

  6. String字符串类课后作业

    String动手动脑和课后作业 请运行以下示例代码StringPool.java,查看其输出结果.如何解释这样的输出结果?从中你能总结出什么? 结果: 总结:在Java中,内容相同的字串常量(&quo ...

  7. C++常用的string字符串截断函数

    C++中经常会用到标准库函数库(STL)的string字符串类,跟其他语言的字符串类相比有所缺陷.这里就分享下我经常用到的两个字符串截断函数: #include <iostream> #i ...

  8. Java:字符串类String的功能介绍

    在java中,字符串是一个比较常用的类,因为代码中基本上处理的很多数据都是字符串类型的,因此,掌握字符串类的具体用法显得很重要了. 它的主要功能有如下几种:获取.判断.转换.替换.切割.字串的获取.大 ...

  9. 设计一个字符串类String(C++练习题)

    要求:设计一个字符串类String,可以求字符串长度,可以连接两个串(如,s1=“计算机”,s2=“软件”,s1与s2连接得到“计算机软件”),并且重载“=”运算符进行字符串赋值,编写主程序实现:s1 ...

随机推荐

  1. Object-C,遍历目录

    最近武汉连续下雨很多天,降温了2次,温度一下子由28度到14度,再到8度,手太冷了. 加上最近发生了一些比较棘手的家庭琐事,最近没心情继续学习Object-C. 后来,我想明白了,心情不好的时候,还是 ...

  2. django-xadmin定制之分页显示数量

    环境:xadmin-for-python3 python3.5.2 django1.9.12 主要思路:利用django-xadmin的插件原理和原有分页插件的逻辑,单独定义一个分页显示数插件,效果如 ...

  3. select &amp; epoll

    同步.异步.堵塞和非堵塞差别 同步:发出一个功能调用时.在没有得到结果之前,该调用就不返回 异步:当一个异步过程调用发出后.调用者不能立马得到结果.实际处理这个调用的部件在完毕后.通过状态.通知和回调 ...

  4. Win8.1应用开发之文件操作

    在操作文件之前,先相应用的应用功能声明进行设定.用户通过C#(非UI)对win8.1上的文件进行訪问,仅仅能局限于图片,音乐,视频和文档四个目录. 而通过文件选取器则能訪问到整个系统的文件. (一)应 ...

  5. 在Mac OS X上安装使用lazarus 1.6.4

    一直觉得delphi的OO做得比C++还完善, 但如今日落西真是让人感到唏嘘,  这并不意味着delphi比C++差, 它的创始人被微软挖墙脚后创造了C#系列开发工具, 设计理念大部分与Delphi相 ...

  6. 灵活的运用Model类

    1.定义接口 using System; using System.Collections.Generic; using System.Linq; using System.Web; namespac ...

  7. libsvm 的使用

    1. libsvm 支持的SVM模型 官网地址:LIBSVM – A Library for Support Vector Machines libsvm 支持的 SVM 模型如下(C:classif ...

  8. 是时候抛弃web.xml了?

    你是否再为配置文件web.xml容易出错而烦恼?是否为web.xml文件存放位置而不知所措?是否为web.xml为什么要这样配?怎么才能更好的配置web.xml而烦恼?那么一种新的方式出现了: spr ...

  9. 转:Java读写文件各种方法及性能比较

    干Java这么久,一直在做WEB相关的项目,一些基础类差不多都已经忘记.经常想得捡起,但总是因为一些原因,不能如愿. 其实不是没有时间,只是有些时候疲于总结,今得空,下定决心将丢掉的都给捡起来. 文件 ...

  10. HDU 4431 Mahjong 模拟

    http://acm.hdu.edu.cn/showproblem.php?pid=4431 不能说是水题了,具体实现还是很恶心的...几乎优化到哭但是DFS(还加了几个剪枝)还是不行...搜索一直T ...