C++中的string类及常用接口说明
1.string类的介绍
Cplusplus中对于string类的介绍 戳这里
翻译:
- 字符串是表示字符序列的类
- 标准的字符串类提供了对此类对象的支持,其接口类似于标准字符容器的接口,但添加了专门用于操作单字节字符字符串的设计特性。
- string类是使用char(即作为它的字符类型,使用它的默认char_traits和分配器类型(关于模板的更多信息,请参阅basic_string)。
- string类是basic_string模板类的一个实例,它使用char来实例化basic_string模板类,并用char_traits和allocator作为basic_string的默认参数(根于更多的模板信息请参考basic_string)。
- 注意,这个类独立于所使用的编码来处理字节:如果用来处理多字节或变长字符(如UTF-8)的序列,这个类的所有成员(如长度或大小)以及它的迭代器,将仍然按照字节(而不是实际编码的字符)来操作
总结如下:
- string是表示字符串的字符串类
- 该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作。
- string在底层实际是:basic_string模板类的别名,typedef basic_string<char, char_traits, allocator> string;
- 不能操作多字节或者变长字符的序列。
string不是STL容器,string是basic_string类模板的一个实例,string是一个模板类。它使用char来实例basic_string, string集成的操作函数与STL容器中的操作函数大部分很相似, 因为sting本身也是用顺序表来实现的(与vector容器类似)。所以用C++标准程序库中的string来代替C中的char*(C++中还是可以用char*, 这是为了与C保持兼容),是因为它和C中的char*比较起来,不必担心内存是否足够、字符串长度等等,而且作为一个类出现,他集成的操作函数足以完成我们大多数情况下的需要。我们也可以把string看成是C++的基本数据类型。使用string类时,必须包含头文件(#include < string >)以及using namespace std;
2.string类的常用接口说明
2.1常见构造
函数名称 | 功能说明 |
---|---|
string() | 构造空的string类对象 ,即空的字符串 |
string(const char *s) | 用C-string来构造string类对象 |
string(size_t n,char c) | string类对象中包含n个字符c |
string(const string&s) | 拷贝构造函数 |
string(const string&s,size_t n) | 用s中的前n个字符构造新的string类对象 |
#include<iostream>
#include<string>
using namespace std;
int main()
{
string s1;//空字符串
cout << "s1=" << s1 << endl;
string s2("Hello World");//用C-string构造string类对象
cout << "s2=" << s2 << endl;
string s3(10, 'a');//string类对象中包含10个字符a
cout << "s3=" << s3 << endl;
string s4(s2);//拷贝构造
cout << "s4=" << s4 << endl;
string s5(s2, 5);//用s2中的前5个字符构造s5
cout << "s5=" << s5 << endl;
system("pause");
return 0;
}
2.2容量操作
函数名称 | 功能说明 |
---|---|
size_t size() const | 返回字符串的有效字符长度 |
size_t length() const | 返回字符串的有效字符长度 |
size_t capacity() const | 返回字符串空间总大小 |
bool empty() const | 检测字符串是否为空串 是返回true,否则返回false |
void clean() | 清空有效字符串 |
void resize(size_t n,char c) | 将有效字符的个数改成n个,多出的空间用字符c填充 |
void resize(size_t n) | 将有效字符的个数改成n个,多出的空间用0填充 |
void reserve(size_t res_arg=0) | 为字符串预留空间 |
#include<iostream>
#include<string>
using namespace std;
int main()
{
cout << "string类对象的容量操作" << endl;
cout << endl;
string s1("Hello World");
cout << "s1="<<s1 << endl;
cout << "s1的有效长度:" << s1.size() << endl;//有效长度
cout << "s1的容量:" << s1.capacity() << endl;//容量
s1.clear();//清空s1
cout << "s1.clear() 清空s1" << endl;
cout << "s1的有效长度:" << s1.size() << endl;//清空后的大小 容量
cout << "s1的容量:" << s1.capacity() << endl;
cout << endl;
cout << "将s1中的有效字符个数增加到10,多出的位置用a补充" << endl;
s1.resize(10, 'a');//将s1中的有效字符个数增加到10,多出的位置用a补充
cout << s1 << endl;
cout << "s1的有效长度:" << s1.size() << endl;
cout << "s1的容量:" << s1.capacity() << endl;
cout << endl;
cout << "将s1中的有效字符个数增加到15,多处位置用0填充" << endl;
s1.resize(15);//将s1中的有效字符个数增加到15,多处位置用0填充
cout << s1 << endl;
cout << "s1的有效长度:" << s1.size() << endl;
cout << "s1的容量:" << s1.capacity() << endl;
cout << endl;
cout << "将s1中的有效字符数缩减到5" << endl;
s1.resize(5);//将s1中的有效字符数缩减到5
cout << s1 << endl;
cout << "s1的有效长度:" << s1.size() << endl;
cout << "s1的容量:" << s1.capacity() << endl;
cout << endl;
cout << "测试reserve是否会改变string中有效元素个数" << endl;
s1.reserve(30);
cout << "s1的有效长度:" << s1.size() << endl;
cout << "s1的容量:" << s1.capacity() << endl;
cout << endl;
cout<<"测试reserve参数小于string的底层空间大小时,是否会将空间缩小"<<endl;
s1.reserve(10);
cout << "s1的有效长度:" << s1.size() << endl;
cout << "s1的容量:" << s1.capacity() << endl;
system("pause");
return 0;
}
其中s1.resize(15)将s1的有效字符增加到15,多处位置用’/0’填充,但不会打印出来aaaaaaaaaa00000,’/0’并不会打印出来,而其size变成了15。
注意:
- 1.size()与length()方法底层实现原理完全相同,一般情况下基本都是用size()。
- 2.clear()只是将string中有效字符(size)清空,不改变底层空间(capacity)大小。
- 3.resize()在改变元素个数时,如果是将元素个数增多,可能会改变底层容量的大小,如果是将元素个数减少,底层空间总大小不变。
- 4.reserve();为string预留空间,不改变有效元素个数,当reserve()的参数小于string的底层空间时,reserve不会改变容量大小。
2.3访问操作
函数名称 | 功能说明 |
---|---|
char &operate[ ](size_t pos) | 返回pos位置的字符,const string类对象调用 |
const char& operate[ ](size_t pos)const | 返回pos位置的字符,非const string类对象调用 |
#include<iostream>
#include<string>
using namespace std;
int main()
{
cout << "string类对象的访问操作" << endl;
string s1("Hello World");
const string s2("Nothing is possible!");
cout << "s1:" << s1 << endl;
for (size_t i = 0; i < s1.size(); ++i) {
cout << s1[i] << " ";
}
cout << endl;
cout << "s2:" <<s2<< endl;
for (size_t j = 0; j < s2.size(); ++j) {
cout << s2[j] << " ";
}
cout << endl;
s1[0] = 'h';
cout << "s1:" << s1 << endl;
//s2[0] = 'n';代码编译失败,因为const类型对象不能修改
return 0;
}
2.4修改操作
函数名称 | 功能说明 |
---|---|
void push_back(char c) | 在字符串后尾插字符c(尾插) |
string& append (const char* s) | 在字符串后追加一个字符串 |
string& operator+=(const string& str) | 在字符串后追加字符串str |
string& operator+=(const char* s) | 在字符串后追加C个数字符串 |
string& operator+=(char c) | 在字符串后追加字符c |
const char* c_str( )const | 返回C格式字符串 |
size_t find (char c, size_t pos = 0)const | 从字符串pos位置开始往后找字符c,返回该字符在字符串中的位置 |
size_t rfind(char c, size_t pos = npos) | 从字符串pos位置开始往前找字符c,返回该字符在字符串中的位置 |
string substr(size_t pos = 0, size_t n = npos)const | 在str中从pos位置开始,截取n个字符,然后将其返回 |
#include<iostream>
#include<string>
using namespace std;
int main()
{
string s;
s.push_back('H');
cout << "s1后尾插字符H:" << s << endl;
s.append("ello");
cout << "s1后追加字符串ello:" << s << endl;
s += 'W';
cout << "s1后追加字符W:" << s << endl;
s += "orld";
cout << "s1后追加字符串orld:" << s << endl;
cout << "返回C格式字符串:" << s.c_str() << endl;
string str("abcdefg");
cout << "str:" << str << endl;
size_t pos = 0;
size_t pos1 = str.find('d', pos);//在str中从pos开始向后找字符d,并返回d在字符串中的位置
cout << "字符d在字符串str中下标为" << pos1 << "的位置" << endl;
size_t pos2 = str.size();
size_t pos3 = str.rfind('e', pos2);
cout << "字符e在字符串str中下标为" << pos3 << "的位置" << endl;//在str中从pos开始向前找字符e,并返回e在字符串中的位置
string str2 = (str.substr(pos3, 3));//在str中从pos3位置开始,截取3个字符,然后将其返回
cout << "在str中从pos3位置开始,截取3个字符:"<<str2 << endl;
system("pause");
return 0;
}
1.在string尾部追加字符时,s.push_back(‘c’) , s.append(1, ‘c’) , s += 'c’三种的实现方式差不多,一般情况下string类的+=操作用的比较多,+=操作不仅可以连接单个字符,还可以连接字符串。
2.对string操作时,如果能够大概预估到放多少字符,可以先通过reserve把空间预留好。
2.5string类非成员函数
函数名称 | 重载的函数 | 功能说明 |
---|---|---|
operator+ | string operator+ (const string& lhs, const string& rhs); string operator+ (const string& lhs, const char* rhs); string operator+ (const char* lhs, const string& rhs); string operator+ (const string& lhs, char rhs); string operator+ (char lhs, const string& rhs); | 返回字符(串)+字符(串)此函数效率较低 |
operator>> | istream& operator>> (istream& is, string& str); | 输入运算符重载, 输入字符串 |
operator<< | ostream& operator<< (ostream& os, const string& str); | 输出运算符重载, 打印字符串 |
getline | istream& getline (istream& is, string& str, char delim); istream& getline (istream& is, string& str); | 获取一行字符串, char delim, 是结束符标识 |
relational operators | bool operator== (const string& lhs, const string& rhs); bool operator== (const char* lhs, const string& rhs); bool operator== (const string& lhs, const char* rhs); bool operator!= (const string& lhs, const string& rhs); bool operator!= (const char* lhs, const string& rhs); bool operator!= (const string& lhs, const char* rhs); bool operator< (const string& lhs, const string& rhs); bool operator< (const char* lhs, const string& rhs); bool operator< (const string& lhs, const char* rhs); bool operator<= (const string& lhs, const string& rhs); bool operator<= (const char* lhs, const string& rhs); bool operator<= (const string& lhs, const char* rhs); bool operator> (const string& lhs, const string& rhs); bool operator> (const char* lhs, const string& rhs); bool operator> (const string& lhs, const char* rhs); bool operator>= (const string& lhs, const string& rhs); bool operator>= (const char* lhs, const string& rhs); bool operator>= (const string& lhs, const char* rhs); | 比较两个字符串 string和char比较 char和string比较 string和string比较 |
3.实现string类及其常用接口
String.h
#pragma once
#include<iostream>
#include<cstring>
#include<string>
class String {
public:
typedef char* Iterator;
String();//构造空的string类对象 ,即空的字符串
String(const char* s);//用C-string来构造string类对象
String(size_t n, char c);//string类对象中包含n个字符c
String(const String& s);//拷贝构造函数
String(const String& s, size_t n);//用s中的前n个字符构造新的string类对象
String& operator=(const String& s);//s1=s2;
String& operator=(const char* s);
~String();
size_t Size()const; //返回字符串的有效字符长度
size_t Length()const;//返回字符串的有效字符长度
size_t Capacity()const;//返回字符串空间总大小
bool Empty()const;//检测字符串是否为空串 是返回true,否则返回false
void Clean();//清空有效字符串
void Resize(size_t n, char c);//将有效字符的个数改成n个,多出的空间用字符c填充
void Resize(size_t);//将有效字符的个数改成n个,多出的空间用0填充
void Reserve(size_t newcapacity);//为字符串预留空间
char& operator[](size_t pos)const;//返回pos位置的字符,非const string类对象调用
char& operator[](size_t pos);//返回pos位置的字符,const string类对象调用
void Push_back(char c);
void Pop_back(char c);
String& Append(const char* s);
String& Append(size_t,const char c);
String& Append(const String& s);
//返回C格式字符串
const char* c_str()const;
// 返回字符c/字符串s在string中第一次出现的位置
size_t Find(const char c, size_t pos)const;
size_t Find(const char* s, size_t pos)const;
size_t Find(const String& s, size_t pos)const;
size_t Rfind(const char c, size_t pos)const;
size_t Rfind(const char* s, size_t pos)const;
size_t Rfind(const String& s, size_t pos)const;
// 截取string从pos位置开始的n个字符
String Substr(size_t pos, size_t n);
// 在pos位置上插入字符c/字符串str,并返回该字符的位置
String& operator+=(const char c);
String& operator+=(const String& s);
String& operator+=(const char* s);
private:
char* _str;
size_t _size;
size_t _capacity;
};
String.cpp
#include"teststring.h"
#include<iostream>
#include<string>
#include<cstring>
#include<cassert>
//构造空的string类对象 ,即空的字符串
String::String()
:_size(0)
,_capacity(15)
,_str(new char[_capacity]){
}
//用C-string来构造string类对象
String::String(const char* s)
:_size(0)
,_capacity(15)
,_str(new char[_capacity]){
if (s == nullptr) {
assert(false);
}
size_t _size = strlen(s);
_capacity = _size;
strcpy(_str, s);
}
//string类对象中包含n个字符c
String::String(size_t n, char c)
:_size(0)
,_capacity(15)
,_str(new char[_capacity]) {
_size = n;
_capacity = _size;
memset(_str, c, n);
}
//拷贝构造函数
String::String(const String& s)
:_size(0)
, _capacity(15)
, _str(new char[_capacity]) {
if (this == &s) {
return;
}
_size = s._size;
_capacity = s._capacity;
strncpy(_str, s._str, s._size);
}
//用s中的前n个字符构造新的string类对象
String::String(const String& s, size_t n)
:_size(0)
, _capacity(15)
, _str(new char[_capacity]) {
_size = n;
_capacity = _size;
strncpy(_str, s._str, n);
}
String::~String() {
if (_str) {
delete[]_str;
}
_str = nullptr;
_size = 0;
_capacity = 0;
}
//s1=s2;
String& String::operator=(const String& s) {
if (this == &s) {
return;
}
char* pstr = new char[s._capacity];
strcpy(pstr, s._str);
delete[] _str;
_size = s._size;
_capacity = s._capacity;
_str = pstr;
}
String& String::operator=(const char* s) {
if (s == nullptr) {
assert(false);
}
_size = strlen(s);
_capacity = _size;
strcpy(_str, s);
}
//返回字符串的有效字符长度
size_t String::Size()const {
return _size;
}
//返回字符串的有效字符长度
size_t String::Length()const {
return _size;
}
//返回字符串空间总大小
size_t String::Capacity()const {
return _capacity;
}
//检测字符串是否为空串 是返回true,否则返回false
bool String::Empty()const {
return 0 == _size;
}
//清空有效字符串
void String::Clean() {
_size = 0;
_str[_size] = '\0';
}
//将有效字符的个数改成n个,多出的空间用字符c填充
void String::Resize(size_t n, char c) {
if (n > _size) {
if (n > _capacity)
Reserve(n);
memset(_str + _size, c, n - _size);
_size = n;
_str[n] = '\0';
}
}
//将有效字符的个数改成n个,多出的空间用0填充
void String::Resize(size_t n) {
if (n > _size) {
if (n > _capacity)
Reserve(n);
memset(_str + _size, '\0', n - _size);
_size = n;
_str[n] = '\0';
}
}
//为字符串预留空间
void String::Reserve(size_t newcapacity) {
if (newcapacity > _capacity) {
char* str = new char[newcapacity];
strcpy(str, _str);
delete[] _str;
_str = str;
_capacity = newcapacity;
}
}
//返回pos位置的字符,非const string类对象调用
char& String:: operator[](size_t pos)const {
assert(pos < _size);
return _str[pos];
}
//返回pos位置的字符,const string类对象调用
char& String:: operator[](size_t pos) {
assert(pos < _size);
return _str[pos];
}
void String::Push_back(char c) {//abcd _size=4
if (_size == _capacity) {
Reserve(_capacity * 2);
}
_str[_size] = 'c';
_size++;
_str[_size] = '\0';
}
//尾删
void String::Pop_back(char c) {
if (_size)
--_size;
}
String& String::Append(const char* s) {
if (s == nullptr) {
assert(false);
}
int size = _size + strlen(s);
Reserve(size);
strcat(_str, s);
_size = size;
return *this;
}
String& String::Append(size_t n, const char c) {
while (n--) {
Push_back(c);
}
return *this;
}
String& String::Append(const String& s) {
int size = _size + s._size;
Reserve(size);
strcpy(_str, s._str);
_size = size;
return *this;
}
//返回C格式字符串
const char* String::c_str()const {
return _str;
}
// 返回字符c/字符串s在string中第一次出现的位置
size_t String::Find(const char c, size_t pos)const {
if (pos < 0 || pos >= _size) {
return -1;
}
char* ptr = strchr(_str + pos, c);
if (ptr) {
return ptr - _str;
}
else {
return -1;
}
}
size_t String::Find(const char* s, size_t pos)const {
if (s == nullptr) {
assert(false);
}
if (pos < 0 || pos >= _size) {
return -1;
}
char* ptr = strstr(_str + pos, s);
if (ptr) {
return ptr - _str;
}
else {
return -1;
}
}
size_t String::Find(const String& s, size_t pos)const {
if (pos < 0 || pos >= _size) {
return -1;
}
char* ptr = strstr(_str + pos, s._str);
if (ptr) {
return ptr - _str;
}
else {
return -1;
}
}
size_t String::Rfind(const char c, size_t pos)const {
char* ptr = nullptr;
strncpy(ptr, _str, pos);
char* m = nullptr;
if (ptr) {
m = strchr(ptr, c);
}
if (m) {
return m - ptr;
}
else {
return -1;
}
}
size_t String::Rfind(const char* s, size_t pos)const {
if (s == nullptr) {
assert(false);
}
char* ptr = nullptr;
strncpy(ptr, _str, pos);
char* m = nullptr;
if (ptr) {
m = strstr(ptr, s);
}
if (m) {
return m - ptr;
}
else{
return -1;
}
}
size_t String::Rfind(const String& s, size_t pos)const {
char* ptr = new char[pos + 1];
ptr[pos] = 0;
strncpy(ptr, _str, pos);
char* m = nullptr;
if (ptr) {
m = strstr(ptr, _str);
}
if (m) {
return m - ptr;
delete[] ptr;
}
else {
return -1;
delete[] ptr;
}
}
// 截取string从pos位置开始的n个字符
String String::Substr(size_t pos, size_t n) {
String str;
if (pos > _size)
return str;
if (pos + n > _size)
n = _size - pos;//不能超出_str;
str.Reserve(n);
str._size = n;
strncpy(str._str,_str+pos,n);
return str;
}
String& String::operator+=(const char c) {
Push_back(c);
return *this;
}
String& String::operator+=(const String& s) {
int size = _size + s._size;
Reserve(size);
strncpy(_str + _size, s._str, s._size);
_size = size;
return *this;
}
String& String::operator+=(const char* s) {
if (s == nullptr) {
assert(false);
}
int size = strlen(s) + _size;
Reserve(size);
strcpy(_str + _size, s);
_size = size;
return *this;
}