C++string—常用接口介绍+模拟实现+习题讲解
创始人
2024-02-04 00:42:17

如果调试一个程序让你很苦恼,千万不要放弃,成功永远在拐角之后,除非你走到拐角,否则你永远不知道你离他多远,所以,请记住,坚持不懈,直到成功。

 

目录

前言

1.string类的常用接口

1.1string类对象的常见构造:

1.2string类对象的访问及遍历操作

1.3string类对象的容量操作

1.4string类对象的修改操作:

2.string类的模拟实现

3.string类的习题


前言

STL(standard template libaray-标准模板库):是C++标准库的重要组成部分,不仅是一个可复用的组件库,而且是一个包罗数据结构与算法的软件框架。学会使用STL,许多底层的数据结构以及算法都不需要自己重新造轮子,站在前人的肩膀上,健步如飞的快速开发。

本篇文章介绍string类,学习string类我们大致分两个方面进行,首先是学习如何使用库中string接口,然后再通过学习string底层源代码的进行模拟实现接口

在介绍string接口前,首先介绍一个网站可以用来查询C++中的库函数以及STL,后续的学习当中会经常在这个文档上查阅各种接口——https://legacy.cplusplus.com/

1.string类的常用接口

string类包含许多接口,在这里我们主要重点介绍string类的常用接口,对于常用的接口我们需要做到不用查阅文档就可以熟练的使用,对于其它接口,只需要做到知道有这种接口,查阅文档会使用即可

1.1string类对象的常见构造:

函数名称功能说明
string()构造空的string类对象,即空字符串
string(const char* s)用C-string来构造string类对象
string(const string&s)拷贝构造函数
string(size_t n, char c) string类对象中包含n个字符c

1.2string类对象的访问及遍历操作

函数名称功能说明
operator[]返回pos位置的字符,const string类对象调用
范围forC++11支持的更简洁的范围for遍历方式
begin + endbegin获取第一个字符的迭代器 , end获取最后一个字符下一个位置的迭
代器
rebing + rend

rbegin获取最后一个字符下一个位置的迭代器,rend获取第一个字符的迭代器

operator[]:

  范围for:

 上面是两种string类对象常规的遍历方式,下面介绍一种STL中通用的遍历方式就是迭代器

迭代器在行为上像指针一样的类型

 正向遍历:begin + end

 

 反向遍历:rebegin + rend

 以上是关于迭代器正向遍历和反向遍历的两种方式,除此之外,库中还有const修饰的函数

如:

 为什么会存在const修饰的函数呢?通过下面的代码来说明:

这段代码中我们只是想打印这个字符串,并不做任何的修改,因此可以使用引用,这样做就减少了一次拷贝构造,提高程序的效率,所以在库中也定义了const修饰的函数 

 下面来介绍一个在编写代码时的小技巧:

上面两行代码是等价的,在使用熟练之后,如果在编写代码的过程中如果觉得定义rit这个变量时类型过长,可以使用auto这个关键字,因为auto可以自动推导变量类型 

 

1.3string类对象的容量操作

函数名称功能说明
size返回字符串有效长度
length返回字符串有效长度
capacity返回空间总大小
clear清空有效字符
reserve为字符串预留空间
resize将有效字符的个数该成n个,多出的空间用字符c填充
size和length函数是等价的:

 capacity函数:

clear函数:

 reserve函数:

关于reserve这个函数的好处是什么呢?

 string这个类在构造对象的时候,底层是使用动态增长的方式来按需申请和释放内存的,如果在构造之前就知道大概需要多大的空间,就不用频繁的申请内存,有效避免在堆上频繁申请内存,造成内存碎片的问题

resize函数:

功能:将有效字符改成n个,多出的空间用字符c来填充

因此会存在三种情况:

n < size  :删除数据

size < n <= capacity :插入数据

n > capacity :扩容 + 插入数据

第一种情况:

第二种情况: 

第三种情况: 

1.4string类对象的修改操作:

函数名称功能说明
push_back在字符串后面尾插字符c
append在字符串后面追加一个字符串
operator+=在字符串后面追加字符串
c_str返回c格式字符串
find 从字符串pos位置开始往后找字符c,返回该字符在字符串中的位置
rfind从字符串pos位置开始往前找字符c,返回该字符在字符串中的位置
substr在str中从pos位置开始,截取n个字符,然后将其返回
insert在pos位置插入字符
erase删除pos位置处的n个字符
assign将一个字符串拷贝到一个对象中去
replace从pos位置开始,将n个字符改成n个字符

push_back函数:

append函数:

 operator+=:

c_str函数:返回一个指向该字符串首字符的指针

 

 find函数:

rfind函数:

 注:find函数和rfind如果找不到就返回npos

-1是size_t类型转换后就是最大的整型:

substr函数:从pos位置开始,截取n个字符,返回截取字符第一个字符的地址

 

insert函数:

erase函数: 

 assign函数:

 repalce函数:

 

 2.string类的模拟实现

1.定义一个string类:为了和库里的区分将类名定义为String

class String
{
public://成员函数
private://成员变量
};

接口1:

构造函数:

    //无参构造:String(){char* _str = new char[1];_str[0] = '\0';_capacity = _size = 0;}//带参构造:String(const char* str = ""){_size = strlen(str);_capacity = _size;_str = new char[_capacity + 1];strcpy(_str, str);}

接口2:

拷贝构造函数:

//传统写法:String(const String& s){_str = new char[s._capacity + 1];_capacity = s._capacity;_size = s._size;strcpy(_str, s._str);}//现代写法String(const String& s):_str(nullptr),_size(0),_capacity(0){String tmp(s._str);std::swap(_str, tmp._str);std::swap(_size, tmp._size);std::swap(_capacity, tmp._capacity);}//现代写法的优化:void swap(String& s){std::swap(_str, s._str);//内置类型调用算法库里面的std::swap(_size, s._size);std::swap(_capacity, s._capacity);}String(const String& s):_str(nullptr), _size(0), _capacity(0){String tmp(s._str);//this->swap(tmp);swap(tmp);//自定义类型使用自己的swap,避免了使用算法库里面的产生三次深拷贝}

接口3

析构函数:

~String(){delete[] _str;_str = nullptr;_capacity = _size = 0;}

接口4

赋值重载函数:

//传统写法String& operator=(const String& s){if (this != &s){char* tmp = new char[s._capacity + 1];strcpy(tmp, s._str);delete[] _str;_str = tmp;_size = s._size;_capacity = s._capacity;}return *this;}//现代写法:String& operator=(const String& s){if (this != &s){String tmp(s);swap(tmp);}return *this;}//现代写法的优化String& operator=(String s){if (this != &s){swap(s);}return *this;}

接口5

operator[]:

char& operator[](size_t pos){return _str[pos];}

接口6

size():

size_t size(){return _size;}

接口7

capacity():

size_t capacity()
{return _capacity;
}

接口8:

c_str():

char* c_str()
{return _str;
}

接口9:

begin和end

typedef char* iterator;iterator begin(){return _str;}iterator end(){return _str + _size;}

接口10

reserve():

void reserve(int n){if (n > _capacity){char* tmp = new char[n + 1];strcpy(tmp, _str);delete[] _str;_str = tmp;_capacity = n;}}

接口11

push_back():

void push_back(char ch){if (_size == _capacity){int newCapacity = _capacity == 0 ? 4 : _capacity * 2;reserve(newCapacity);}_str[_size] = ch;++_size;_str[_size] = '\0';}

接口12

append():

void append(const char* str){size_t len = strlen(str);if (_size+len > _capacity){reserve(_size + len);}strcat(_str, str);_size += len;}

接口13

operator+=():

    //+=字符String& operator+=(const char ch){push_back(ch);return *this;}//+=字符串String& operator+=(const char* str){append(str);return *this;}

接口14

insert():

//插入字符String& insert(size_t pos, const char ch){assert(pos < _size);if (_size == _capacity){int newCapacity = _capacity == 0 ? 4 : _capacity * 2;reserve(newCapacity);}//写法1:/*	int end = _size;while (end >= (int)pos){_str[end + 1] = _str[end];--end;}*///写法2:int end = _size + 1;while (end > pos){_str[end] = _str[end - 1];--end;}_str[pos] = ch;_size++;return *this;}//插入字符串:String& insert(size_t pos, const char* str){size_t len = strlen(str);if (_size + len > _capacity){reserve(_size + len);}//写法1:/*	int end = _size;while (end >= (int)pos){_str[end + len] = _str[end];--end;}*///写法2:int end = _size + len;while (end >= pos + len){_str[end] = _str[end - len];--end;}strncpy(_str + pos, str, len);_size += len;return *this;}

接口15

erase():

String& erase(size_t pos, size_t len = npos){assert(pos < _size);if (len == npos || len >= _size - pos){_str[pos] = '\0';_size = pos;}else{strcpy(_str + pos, _str + pos + len);_size -= len;}return *this;}

接口16

find():

//查找字符size_t find(char ch, size_t pos = 0){assert(pos < _size);int i = pos;while (_size--){if (_str[i] == ch){return i;}i++;}return npos;}//查找字符串:size_t find(const char* str, size_t pos = 0){assert(pos < _size);char* ptr = strstr(_str + pos, str);if (ptr == nullptr){return npos;}else{return ptr - _str;}}

接口17

clear():

void clear()
{_str[0] = '\0';_size = 0;
}

接口18

resize():

void resize(size_t n, char ch = '\0'){if (n > _capacity){reserve(n);for (int i = _size; i < n; i++){_str[i] = ch;}_size = n;_str[_size] = '\0';}else{_str[_size] = '\0';_size = n;}}

流提取:oparetor<<()

ostream& operator<<(ostream& out, String& s)
{for (int i = 0; i < s.size(); i++){out << s[i];}return out;
}

流插入:oparetor>>()

istream& operator>>(istream& in, String& s)
{s.clear();//第一种写法//char ch = in.get();等于空格或者换行就就结束了!//while (ch != ' ' && ch != '\n')//{//	s += ch;//	ch = in.get();//}// 第一种写法的优化//减少频繁扩容char buf[128] = { 0 };int i = 0;char ch = in.get();while (ch != ' ' && ch != '\n'){if (i == 127){s += buf;i = 0;}buf[i++] = ch;ch = in.get();}//不足128或者剩下的:if (i > 0){buf[i] = '\0';s += buf;}return in;
}

 3.string类的习题

习题1:字符串转换成整数oj链接

class Solution {
public:int StrToInt(string str) {int sum = 0;int flag = 1;for(int i = 0; i= '0' && str[i] <= '9')){return 0;}else{sum = sum*10 + str[i] - '0';}}return sum*flag;}
};

习题2:字符串相加oj链接

class Solution {
public:string addStrings(string num1, string num2) {int end1 = num1.size()-1;int end2 = num2.size()-1;int carry = 0;string retStr;retStr.reserve(max(num1.size(),num2.size()+1));while(end1 >= 0 || end2 >= 0){int val1 = end1 >= 0 ? num1[end1] - '0' : 0;int val2 = end2 >= 0 ? num2[end2] - '0' : 0;int ret = val1 + val2 + carry;carry = ret / 10;ret %= 10;retStr += '0' + ret;end1--;end2--;}if(carry == 1)retStr += '1';reverse(retStr.begin(),retStr.end());return retStr;}
};

习题4:仅仅反转字母oj链接

class Solution {
public:string reverseOnlyLetters(string s) {int begin = 0;int end = s.size()- 1;while(begin < end){while(begin < end && !isalpha(s[begin])){++begin;}while(begin < end && !isalpha(s[end])){--end;}swap(s[begin],s[end]);++begin;--end;}return s;}
};

习题5:字符串中只出现一次的字符oj链接

class Solution {
public:int firstUniqChar(string s) {int str[26] = { 0 };for(auto& ch : s){str[ch - 'a']++;}for(int i = 0; i < s.size(); i++){if(str[s[i]-'a'] == 1)return i;}return -1;}
};

习题6:字符串中最后一个单词的长度oj链接

#include
#include
using namespace std;
int main()
{string s;getline(cin,s);size_t pos = s.rfind(' ');cout<

习题7:验证字符串是否回文oj链接

class Solution {
public:bool isCharacter(char ch){return ((ch >= '0' && ch <= '9')||(ch >= 'a' && ch <= 'z')||(ch >= 'A' && ch <= 'Z'));}bool isPalindrome(string s) {for(auto& ch : s){if(ch >= 'A' && ch <= 'Z'){ch +=32;}}int begin = 0;int end = s.size()-1;while(begin < end){while(begin < end && !isCharacter(s[begin])){++begin;}while(begin < end && !isCharacter(s[end])){--end;}if(s[begin] != s[end])return false;else{++begin;--end;}}return true;}
};

习题8:反转字符串(区间部分反转)oj链接

class Solution {
public:string reverseStr(string s, int k) {int n = s.size();for(int i = 0; i

习题9:反转字符串中的单词oj链接

class Solution {
public:string reverseWords(string s) {int len = s.size();int begin = 0;int end = 0;while(begin < len){while(s[end] != ' ' && s[end] != '\0'){++end;}int end1 = end+1;while(begin < end){swap(s[begin],s[end-1]);++begin;--end;}begin = end1;end = end1;}return s;}
};

相关内容

热门资讯

埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...