C++ 字符串梳理
0、概要
先介绍C++继承的C风格字符串,再重点说明C++自己发展的string类。最后谈谈两者之间的联系和区别。
1、C- 字符串
1.1、字符数组即是字符串
C++在C之上发展而来,并且保证任何C程序都是合法的C++程序,所以C++必须支持C风格的字符串,即C-string。
C并没有string类型,而是通过char数组实现字符串,即:字符串是以空字符\0
结尾的字符数组。
char charr[] = {'H', 'e', 'l', 'l', 'o', '\0'}; //遵循数组的初始化方式
char charr1[] = "Hello"; //更加方便实用,C在存储的时候自动在末尾添加空字符\0
上面两个语句声明并初始化了一个字符串"Hello"。
本质上,C只有字符数组没有字符串。C将字符串拆解成字符数组,存储在连续的存储单元内,数组名记录了第一个字符的位置,空字符\0
代表了字符串结尾。如下例:
char charr2[] = {'H', 'e', 'l', '\0', 'l', 'o','\0'}; //charr2="Hel"
char charr3[] = {'H', 'e', 'l', 'l', 'o'}; //charr3会一直读取到内存上的\0为止
1.2、C-style 字符串的简单使用
//C-style字符串的简单使用
char chars1[15] = {'H', 'e', 'l', 'l', 'o', ' ', '\0'}; //数组方式初始化
char chars2[] = "C++"; //字符串常量初始化
char chars3[20]; //不初始化必须给出数组大小
//字符串连接
strcat(chars1,chars2); //chars1="Hello C++"
cout<<chars1<<endl;
//字符串复制
strcpy(chars3,chars1); //chars3=chars1="Hello C++"
cout<<chars3<<endl;
//字符串比较(0表示相等)
cout<<"chars1 == chars3 ? "<<strcmp(chars1,chars3)<<endl;
//字符串大小
cout<<"chars2 有 "<<strlen(chars2)<<" 字符," //3个字符
<<"占 "<<sizeof chars2<<" 字节."<<endl; //4个字节
2、C++ string类
C的字符数组有很多不便,尤其是字符数组的大小必须固定,定义的时候,大了浪费内存,小了字符串的存储越界,并且不支持字符数组之间的赋值等操作,所以C++标准库提供了string类作为字符串类,在string
头文件中。
从定义上:
typedef basic_string<char> string
string类其实是一个实例化的模板类。
2.1、常用方法
-
构造器:
- 默认空串:
string()
- 复制已有字符串:
string(const string& str)
- 复制已有C字符串:
string(const char* s)
- 截取子串:
string(const string& str, size_t pos, size_t len=npos)
- 从C字符串提取前缀:
string(const char* s, size_t n)
- 填充n个字符c:
string(size_t n, char c)
- 默认空串:
-
**赋值(=):**string支持string类型、C字符串类型、字符串常量、char类型的赋值。
string s1="Hello"; //字符串常量赋值 string s2=s1; //string类型赋值 char[] chs[]="C++"; string s3=chs; //char[]类型赋值 string s4='A'; //char类型赋值 string s5=65; //s5="A",65,对应的字符为A,char类型赋值
-
大小与容量:
string对象会根据字符串的大小调整分配空间大小,但是并不是每一次都调整大小,导致string有3个大小相关的量:(1)size(length): 当前的字符串长度;(2)capacity(容量):当前分配的内存空间可存储的最大字符串长度,会根据字符串的值变动发生变化;(3)max_size(最大值):当前系统理论上支持的最大字符串长度,限制capacity,capacity超过时发生length_error。实际应用中,只关心size的大小,其它两个常常不用。
- 获取字符串长度:
size()
或length()
,效果一样 - 判断是否为空:
empty()
- 改变字符串长度:
resize(size_t n)
和resize(size_t n, char c)
。n < s.size()时,截取前面n个字符;n>s.size()时,填充字符c直到n个字符,没有指明c则用空字符\0填充。 - 获取当前容量:
capacity()
- 获取支持的字符串最大长度:
max_size()
- 手动分配容量:
reserve(size_t n=0)
- 获取字符串长度:
-
成员获取:
- 成员获取方法(推荐):
at(size_t pos)
, 返回下标为pos的字符。 - 下标运算符[ ]:s[pos]表示下标为pos的字符。
- 首尾字符:
front()
和back()
at()方法和 [ ] 运算符的区别在于前者进行下标检测,后者没有,推荐使用前者。但是后者可以作为左值。
- 成员获取方法(推荐):
-
字符串修改:
-
插入:
insert()
。insert() 有多种重载方式,支持插入字符、字符串、插入重复字符串等。string str="to be question"; string str2="the "; string str3="or not to be"; str.insert(6,str2); // to be (the )question str.insert(6,str3,3,4); // to be (not )the question str.insert(10,"that is cool",8); // to be not (that is )the question str.insert(10,"to be "); // to be not (to be )that is the question str.insert(15,2,':'); // to be not to be(::) that is the question
-
追加:
append()
.可以看成在末尾插入,不用指明插入位置,其它使用与insert()
一样。 -
替换:
replace()
string str="Hello World"; str.replace(6,5,"C++"); //"Hello C++" str.replace(5,1,'+'); //"Hello+C++",替换当个字符只能这样,或者str[5]='+'
-
删除:
erase(size_t pos, size_t len=npos)
.删除pos开始的len个字符,没有指明len会把pos之后的全删除。len为1即可删除单个字符。 -
清空:
clear()
. -
push和pop一个字符:
push_back(char c)
和pop_back()
,分别在末尾剔除和添加字符。
-
-
字符串操作:
-
获取子串:
substr(size_t pos=0, size_t len=npos)
。 -
转化为c-style字符串:
c_str()
. -
获取字符序列数组:
data()
。与c_str()
的区别在于后者包含最后的空字符\0,前者没有。 -
复制:`copy( char* s, size_t len, size_t pos=0)
string str="This is a string"; char chars[20]; str.copy(chars, 10, 6); //chars="string"
-
赋值:
assign()
可以把字符串或其子串赋给目的字符串。 -
查找:
find()
和rfind()
,前者返回第一个找到的位置,后者(right find)从右查找第一个(即最后一个)位置。find_first_of()
和find_last_of()
.查找单个字符时,与上面一致。当参数为字符串时,表示查找字符串中任意一个字符。find_first_not_of()
和find_last_not_of()
, 意思明确。
string str="This is a string"; str.find("string"); //10 str.find_first_of("string"); //2,第三个字符i符合。
-
-
字符串比较:
字符串的比较是以字典排序为基础的。如:’‘ABC’’ > “ab” > “abc”。
- 比较符号:string类支持
>
,<
,>=
,!=
等进行比较,还能和c-string比较。 compare()
方法:支持部分比较,如果前者在
- 比较符号:string类支持
3、C-string和string类
本质上,二者是完全不一样的。C-string是字符串数组,本质上是数组,string是面向对象衍生出来的类。 这种不同,导致很多使用方式的不同,C-string需要借助函数完成,而string对象往往依靠成员方法实现。如:strlen(chars)
和str.size()
。
在C++中,字符串更推荐使用string类,它较C-string有很多优点:面向对象思想、动态空间分配、使用方便等。
但是,C++也无法抛弃C-string,难免会有交叉使用,你看各种string成员都支持了C-string。
3.1、二者的转化
很多时候,两者还是无法通用的,比如很多老函数只支持C-string参数。所以有必要额外注意一下二者的转化。
char cstr[20]="This is a string";
string str(cstr); //C-string转为string
cstr=str.c_str(); //string转为C-string