目录
string - C++ Reference
1 容量相关
1.1 size/length
1.2 capacity
1.3 resize
1.4 reserve
1.5 empty
2 运算符重载
2.1 operator=
2.2 operator[]
2.3 operator+(非成员函数)
2.4 operator+=
2.5 operator>> && operator<<(非成员函数)
3 增删查改的接口
3.1 push_back
3.2 append
3.3 insert
3.4 erase
3.5 assign
3.6 find
string - C++ Reference
1 容量相关
1.1 size/length
size和length表示string里存储的有效数据的大小/长度。
可以用来for循环遍历string:
string str("hello string");
for(int i = 0;i < str.size();++i)
{
cout<<str[i];//[]重载
}
string str("hello string");
for(int i = 0;i < str.length();++i)
{
cout<<str[i];//[]重载
}
注:
length用来表示线性数据结构的有效数据长度大小,size既可以用来表示线性数据结构的有效数据大小、也可以用来表示非线性结构的有效数据大小,可以说size是通用的。
1.2 capacity
capacity表示已经分配的空间的大小,通常capacity>=size/length
1.3 resize
顾名思义,改变string对象的size,有两个函数重载
体现为两个方面:
①如果传入的n<原先的长度,仅仅会删除数据,不作数据修改,因此有效重载函数形式为
void resize(size_t n)
vs编译器:
g++:
②如果传入的n>原先的长度,不仅会改变容量,而且可以指定增加的数据,因此有效函数重载形式为:
void resize (size_t n)
void resize (size_t n, char c)
vs编译器:
指定增加的字符为'x':
不指定增加的字符,可能放入的都是\0:
g++:
不指定增加的字符,可能放入的都是\0:
1.4 reserve
顾名思义,reserve会改变capacity,而不会改变数据,因此传入的参数n大于原先的capacity才有效果!
vs编译器:
g++:
1.5 empty
函数返回类型为真或者假
2 运算符重载
2.1 operator=
我们原本以为的赋值运算符重载:
第二行还有报错,报错信息是:
实际上这并不是赋值运算符重载,实际的运算符重载应该是这样的:
vs下=号的颜色都变了,说明两次=的作用是不一样的。为什么呢?
这下我们明白了,之所以第二次是赋值运算符重载,是因为s1、s2、s3都已经初始化好了,而且都是调用的默认构造函数string() 。
赋值运算符的运算顺序是自右向左的,s1先赋值给s2,s2再赋值给s3。
2.2 operator[]
operator[]为我们提供了通过下标直接访问字符串内容的便利,有两种函数重载,一种给普通对象,另一种给const对象。
2.3 operator+(非成员函数)
Concatenate strings:连接字符或字符串
用法:
为什么这个重载是非成员函数呢?
我们都知道成员函数的第一个参数是隐藏的this指针,指向实例化出来的对象, 因此如果把+重载写在类里面也就是成员函数,第一个参数就必然是实例化出来的对象,而相加的两个对象不必一定要有this,可以是其他的两个对象,所以STL库就把它设计成非成员函数。
2.4 operator+=
官网里的例子:
和赋值重载一样,需要先进行初始化调用构造函数才能进行+=重载!
operator+=可以很方便地进行字符串尾插的操作,相当于尾插,尾插前先检查容量,容量不够先扩容再尾插。下面还有append、insert等的接口函数,也是用来进行字符串增加的。
2.5 operator>> && operator<<(非成员函数)
为了方便输入和直接输出string里的内容,设计出了流插入和流提取的重载。
这两个必须设计成非成员函数,否则就会导致cout和str的顺序颠倒:str<<cout
因为左右操作数和函数的传参类型要一致,成员函数的第一个参数永远是this指针!
3 增删查改的接口
3.1 push_back
尾插会先检查容量,容量不够先扩容,然后在进行尾插操作。尾插结束后再补一个\0,模拟一下:
void push_back(char c)
{
if (_capacity == _size)
{
reserve(_capacity == 0 ? 4 : _capacity * 2);
}
_str[_size] = c;
_size++;
_str[_size] = '\0';
}
3.2 append
append提供了六种函数重载,可以看作push_back的plus版本。
string s = "hello";
string _s = " string";
s.append(_s);//hello string
s.append(_s,0,3);//hello st
s.append(" string");//hello string
s.append(" string", 2);//hello s
s.append(5,'x');//helloxxxxx
s.append(_s.begin(),_s.begin()+2);//hello s
讲解一下第二种和第四种:
substring(2):
string& append (const string& str, size_t subpos, size_t sublen)
string s = "hello";
string _s = " string";
s.append(_s,0,3);//hello st
功能:将副串_s的一部分尾插至主串s之后。
注:
subpos必须小于等于sublen,否则就会:
如果sublen大于strlen(_s),编译器会多开空间吗?
vs编译器:
g++:
答案是不会!
buffer(4):
string& append (const char* s, size_t n)
string s = "hello";
s.append(" string", 3);
cout<<s;//hello st
功能:将常量字符串的一部分尾插至s。
注:
如果传入的参数n大于strlen(s),编译器会多开空间吗?
vs编译器:
g++:
答案是会的!
3.3 insert
由于顺序表头插的时间复杂度为O(n),效率较低,所以STL库并没有实现string的头插接口,而是设计了一个insert,可以用来在pos位置插入字符或字符串,特殊的当pos为0时,就相当于头插。
其中前四种的设计和上面append的设计类似,后三种多了迭代器的传参:
void insert(iterator p,size_t n,char c);
iterator insert (iterator p, char c);
template <class InputIterator>
void insert (iterator p, InputIterator first, InputIterator last);
第一种的用法:
第二种用法:
第三种用法:
3.4 erase
顾名思义,删除字符串中的字符。
用法:
第一种:
缺省参数pos=0,len=(size_t)(-1)=2^32-1
第二种:
传入迭代器,删除迭代器指向的单个字符,并返回迭代器。
顺序是先删除h再把删除后的s.begin()赋值给it。
第三种:
范围删除并返回迭代器,范围是[first,last),左闭右开!
3.5 assign
assign的用法其实就是新串代替旧串,举一个例子就行:
3.6 find
find还是挺好用的,至少不用自己写字符串查找算法,找到了就返回找到的最开始的位置,找不到就返回(size_t)(-1)。