Android C++系列:string最佳实践

简介: 在C语言中我们操作String要相对麻烦些,每次字符串拼接都要重新开辟空间,再把数据拷贝进去,使用上没有那么便捷。

image.png


1. 背景介绍


在Java中操作字符串比较简单,这里简单介绍下Java字符串操作相关接口。


字符串拼接直接用+号既可,字符串比较实用equel方法,同时还提供了StringBuilder和StringBuffer可变的字符串。它们继承了同一个抽象的字符串父类:AbstractStringBuilder


StringBuffer是线程安全,StringBuilder线程不安全。因为 StringBuffer 的所有公开方法都是 synchronized 修饰的,而 StringBuilder 并没有 synchronized修饰;StringBuffer 每次 toString 都会直接使用缓存区的 toStringCache 值来构造一个字符串,而 StringBuilder 则每次都需要复制一次字符数组,再构造一个字符串。所以,缓存冲这也是对 StringBuffer 的一个优化吧,不过 StringBuffer 的这个toString 方法仍然是同步的。


在C语言中我们操作String要相对麻烦些,每次字符串拼接都要重新开辟空间,再把数据拷贝进去,使用上没有那么便捷。

C++标准库中为我们实现了std::string字符串类,本文我们系统的介绍std::string类。


2. 初始化std::string


string也是C++的一个类,跟其他普通类类似,string也提供了以下几种初始化方法:


#include <string>
using std::string;
//默认初始化成空字符串
string s1;
//拷贝初始化,等价于string s2(s1);
string s2=s1;
//拷贝初始化,是字符串字面值的副本,等价于string s3("hello");
string s3 = "hello";
//初始化为由连续n个字符c组成的串
string s4(3,'a');


3. string常用操作


C++中定义在类上的操作除了方法还有操作符,这里我们介绍C++常用操作。


3.1 读写string


读写string主要用到string类上定义的操作符:<<>>:


string s;
//将标准输入内容写入到自字符串s
cin >> s;
//将字符串输出给标准输出
count << s << end;


string对象的<<>>操作返回运算符左侧的运算对象作为结果:


string s1,s2;
//第一个输入写到s1,第二个输入写到s2
cin >> s1 >> s2;
cout << s1 << s2 <<endl;


与标准输入输出相关的还有读取一行,使用getline方法:


string str;
getline(cin, line);


3.2 获取字符串长度


通过成员变量size获取字符串长度;


还可以通过empty函数判断string对象字符数是否为零。


size函数返回的不是int或者unsinged int,二是返回的是string::size_type类型。


为什么要有这么一个类型呢?因为这样定义提箱了标准库类型与机器无关的特性。


**注意:**其实size函数返回的还是一个无符号整形,只是做了一层封装,因此我们在表达式计算中要避免既有size返回类型的同时又有int型。因为例如,假设x是一个具有负值的int,则表达式s.size()< x的判断结果肯定是true,因为负值x会自动地转换成一个比较大的无符号值。


3.3 string字符串的比较


java中我们不能用==来比较两个字符串,它比较的是地址,要用equal。在C++中用相等性运算符(==和!=)来检验两个string对象是否相等。相等意味着它们的长度相同并且所包含的字符也全相同。


C++中还可以用关系运算符<、<=、>、>=来检验一个string对象是否小于、小于等于、大于、大于等于另外一个string对象。


3.4 字符串相加


两个string对象相加得到一个新的string对象,其内容是把左侧的运算对象与右侧的运算对象串接而成。这个和Java中字符串相加很类似。


C++标准库允许把字符字面值和字符串字面值转换成string对象,所以在需要string对象的地方可以使用这两种字面值来替代。比如:


string s1 = "hello";
string s2 = "world";
string s3 = s1 + "," + s2 + "\n";


**注意:**当把string对象、字符字面值、字符串字面值在一条语句中相加时,必须确保每个加法运算符(+)的两侧的运算对象至少有一个是string。比如:


string s = "hello" + "world";//错误
string s1 = "world";
string s2 = "hello" + "," + s1;//错误


虽然我们不会去这样搞,但是也要知道这种是有语法错误的。


有这个问题的原因是C++为了与C兼容,C++语言的字符串字面值并不是标准库类型string的对象。字符串字面值与string不是同样的类型。


4. string的字符遍历


string其实可以理解成一个字符的集合,既然是集合就要涉及遍历。比如将string中所有字符变为小写,查看特定字符是否存在等。


在cctype头文件中定义了一组标准库函数做字符处理相关工作:


  • isalnum:是否为字母或数字
  • isalpha:是否为字母;
  • iscntrl:是否为控制字符
  • isdigit:是否为数字
  • isgraph:不是空格但可打印
  • islower:是否是小写字母
  • isprint:是可打印字符
  • ispunct:是否是标点符号
  • isspace:是否为空白(空格、制表符、回车、换行、进纸)
  • isupper:是否为大写
  • isxdigit:是否是十六进制数字
  • tolower:如果是大写字母,返回对应小写字母
  • toupper:如果是小写字母,返回对应大写字母


最佳实践: C++标准库中除了定义C++语言特有的功能外,也兼容了C语言的标准库。比如C语言的头文件为name.h,C++则命名为cname。建议使用C++版本的C标准库头文件。


遍历字符串,可以使用for语句:


for(declaration: expression)
  statement


示例:


string str("1234566");
for(auto c : str){
  cout << c <<endl;
}


但是如果我们想要改变string对象中的字符的值,必须把循环变量定义成引用类型:


string s("ABCDEFG");
//转换成小写
for(auto &c : s){
  c = tolower(c);
}
cout << s << endl;


除了使用for循环,还可以使用下标运算符[]访问字符串中特定位置的字符,返回值是该位置上字符的引用(因为是引用所以我们可以直接改变这个值):


cout << s[0] << endl;


不像Java如果下标越界直接崩溃,C++中如果下标越界将引发不可预知的结果,所以我们在使用下标运算符时一定要对下标范围做判断。


**最佳实践:**任何表达式只要它的值是一个整形就能作为索引。如果某个索引是带符号类型的值将自动转换成由string::size_type表达的无符号类型。有一个简单的技巧,我们总是设下标类型为string:size_type,因为它是无符号数,可以确保下标不会小于0,只要保证下标小于size()的值即可。


5.总结


本文介绍了C++标准库std::string的基本操作以及常用的函数,介绍了string字符遍历的方法,并总结了一些使用小技巧。

目录
相关文章
|
1月前
|
移动开发 监控 Android开发
Android & iOS 使用 ARMS 用户体验监控(RUM)的最佳实践
本文主要介绍了 ARMS 用户体验监控的基本功能特性,并介绍了在几种常见场景下的最佳实践。
|
1月前
|
C++ 容器
|
1月前
|
存储 安全 C++
【C++打怪之路Lv8】-- string类
【C++打怪之路Lv8】-- string类
21 1
|
1月前
|
C++ 容器
|
1月前
|
C++ 容器
|
1月前
|
存储 C++ 容器
|
1月前
|
安全 C语言 C++
【C++篇】探寻C++ STL之美:从string类的基础到高级操作的全面解析
【C++篇】探寻C++ STL之美:从string类的基础到高级操作的全面解析
34 4
|
1月前
|
存储 编译器 程序员
【C++篇】手撕 C++ string 类:从零实现到深入剖析的模拟之路
【C++篇】手撕 C++ string 类:从零实现到深入剖析的模拟之路
63 2
|
1月前
|
编译器 C语言 C++
【C++】C++ STL 探索:String的使用与理解(三)
【C++】C++ STL 探索:String的使用与理解
|
1月前
|
存储 编译器 C++
【C++】C++ STL 探索:String的使用与理解(二)
【C++】C++ STL 探索:String的使用与理解