当前位置: 首页 > news >正文

【C++】透析string类

                                个人主页:CSDN_小八哥向前冲~

                                 所属专栏:C++入门


目录

string类介绍

auto和范围for

auto关键字

范围for

string类常用接口说明

string类常见构造

string类容量操作

string类的访问及遍历操作

string类修改操作

string的结构说明

vs下的结构

G++下的结构

string经典题目

仅仅反转字母

字符串中的第一个字符

字符串最后一个单词的长度

验证回文字符

字符串相加

string类的模拟实现

码源


string类介绍

关于string的详细介绍,我们可以去C++官网查询!

官网:https://cplusplus.com/

下面我只做一些简单介绍!

auto和范围for

auto关键字

  • 在早期C/C++中auto的含义是:使用auto修饰的变量,是具有自动存储器的局部变量,后来这个 不重要了。C++11中,标准委员会变废为宝赋予了auto全新的含义即:auto不再是一个存储类型 指示符,而是作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期 推导而得。
  • 用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须加&
  • 当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际 只对第一个类型进行推导,然后用推导出来的类型定义其他变量。
  • auto不能作为函数的参数,可以做返回值,但是建议谨慎使用
  • auto不能直接用来声明数组

范围for

  • 对于一个有范围的集合而言,由程序员来说明循环的范围是多余的,有时候还会容易犯错误。因此 C++11中引入了基于范围的for循环。for循环后的括号由冒号“ :”分为两部分:第一部分是范围 内用于迭代的变量,第二部分则表示被迭代的范围,自动迭代,自动取数据,自动判断结束。
  • 范围for可以作用到数组和容器对象上进行遍历
  • 范围for的底层很简单,容器遍历实际就是替换为迭代器,这个从汇编层也可以看到。

使用:

string类常用接口说明

注意:这些所有函数可以去C++官网查看,有详细讲解!

string类常见构造

我们来详细演示一下!

string类容量操作

注意一下这些函数的要点!

我们依然来演示一下!

string类的访问及遍历操作

函数:

我们来演示一下!

string类修改操作

这些重要函数我们要了然于心!

演示一下!

string的结构说明

vs下的结构

真实的情况:

G++下的结构

我们来试试几个题目练习一下!

string经典题目

仅仅反转字母

题目:【力扣】仅仅反转字符

思路:

定义两个指针,一个在前,一个在后,当两个指针指向的都是字母的时候就开始交换!

代码:

class Solution {
public://判断是不是字母bool isnumber(const char& tmp){if(tmp<='z'&&tmp>='a') return true;if(tmp<='Z'&&tmp>='A') return true;return false;}string reverseOnlyLetters(string s) {size_t begin=0,end=s.size()-1;while(begin<end){//找到字母while(begin<end&&!isnumber(s[begin])) begin++;while(begin<end&&!isnumber(s[end])) end--;//交换字母swap(s[begin++],s[end--]);}return s;}
};

字符串中的第一个字符

题目:字符串中的第一个字符

思路:

遍历字符串,利用映射原理将字符全部映射进一个数组,然后再次遍历字符串!

代码:

class Solution {
public:int firstUniqChar(string s) {int count[26]={0};//利用映射for(auto& e:s) count[e-'a']++;//再次遍历一遍数组for(int i=0;i<s.size();i++){if(count[s[i]-'a']==1) return i;}return -1;}
};

字符串最后一个单词的长度

题目:【牛客】字符串最后一个单词的长度

思路:

注意如果我们用cin去输入,那么到了空格就会停下,我们用getline就能避免这个情况!

代码:

int main() {string s1;getline(cin, s1, '\n');size_t pos = s1.rfind(' ');cout << s1.size() - (pos + 1) << endl;return 0;
}

验证回文字符

题目:【力扣】验证回文字符

思路:

先将字符串转化成小写,定义双指针,一前一后,如果两指针指向的是字母或数字,开始判断是否一样!

代码:

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

字符串相加

题目:【力扣】字符串相加

思路:

我们按照数学里面的加减法进位的方式,从各自的字符串末尾开始相加,只是注意好进位,我们算好每位的数字,然后尾插进一个新字符串中,最终将它们翻转一下就行!

代码:

class Solution {
public:string addStrings(string num1, string num2) {int end1=num1.size()-1,end2=num2.size()-1;string s;//进位变量int next=0;while(end1>=0||end2>=0){int val1=end1>=0?num1[end1--]-'0':0;int val2=end2>=0?num2[end2--]-'0':0;int sum=val1+val2+next;next=sum/10;sum%=10;s+=sum+'0';}if(next==1) s+='1';//翻转reverse(s.begin(),s.end());return s;}
};

string类的模拟实现

在这里我们重点说一下拷贝构造,赋值构造,字符串的输入

拷贝构造

通常我们的拷贝构造是这样写的:

string(const string& s)
{//传统写法_str = new char[s._capacity];_capacity = s._capacity;_size = s._size;strcpy(_str, s._str);
}

我们可以改善一下:

		void swap(string& tmp){std::swap(_str, tmp._str);std::swap(_size, tmp._size);std::swap(_capacity, tmp._capacity);}string(const string& s){//传统写法//_str = new char[s._capacity];//_capacity = s._capacity;//_size = s._size;//strcpy(_str, s._str);//现代写法string tmp(s.c_str());swap(tmp);}

解释:构造一个和 s 相同的string类对象tmp,然后将tmp里面的数据和this里面的数据交换 ,最后无用数据tmp出作用域被销毁!

赋值构造也是如此!

传统写法:

string& operator=(string& s)
{//传统写法if (this != &s){delete[] _str;_str = new char[_capacity + 1];strcpy(_str, s._str);_size = s._size;_capacity = s._capacity;}
}

我们也可以相同的手法来改善它!

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

甚至可以进一步完善!

		//或者(现代写法)string& operator=(string tmp){swap(tmp);return *this;}

构造一个新string 类对象这一步浓缩在了函数参数这一步!

字符串的输入jieshi

	istream& operator>>(istream& in, string& s){const size_t N = 256;char buff[N] = { 0 };char ch = 0;ch = in.get();int i = 0;while (ch != ' ' && ch != '\n'){buff[i++] = ch;if (i == N - 1){buff[i] = '\0';s += buff;//尾插i = 0;//重置i}ch = in.get();}if (i > 0)//将剩下的数据尾插{buff[i] = '\0';s += buff;}return in;}

解释:我们相当于创建了一个数组容器,将字符不断插入进这个容器,当容器满的时候,将这些数据插入string 类对象里,如果暂停输入,将剩下的数据再插入进string 类对象里!

码源

String.h文件

#include<iostream>
#include<assert.h>
using namespace std;namespace ywc
{class string{public:typedef char* iterator;iterator begin(){return _str;}iterator end(){return _str + _size;}string(const char* str=""){_size = _capacity = strlen(str);_str = new char[_size + 1];strcpy(_str, str);}void swap(string& tmp){std::swap(_str, tmp._str);std::swap(_size, tmp._size);std::swap(_capacity, tmp._capacity);}string(const string& s){//传统写法//_str = new char[s._capacity];//_capacity = s._capacity;//_size = s._size;//strcpy(_str, s._str);//现代写法string tmp(s.c_str());swap(tmp);}string& operator=(string s){swap(s);return *this;}const char* c_str() const{return _str;}size_t size(){return _size;}size_t capacity(){return _capacity;}char operator[](size_t pos){assert(pos >= 0);return _str[pos];}void reserve(size_t n);void push_back(char ch);string& append(const char* str);string& operator+=(char ch);string& operator+=(const char* str);string& insert(size_t pos, char ch);string& insert(size_t pos, const char* str);string& erease(size_t pos, size_t len);size_t find(char ch, size_t pos = 0);size_t find(const char* str, size_t pos = 0);string substr(size_t pos, size_t len);private:char* _str = nullptr;size_t _size = 0;size_t _capacity = 0;static const size_t npos;};ostream& operator<<(ostream& out, string& s);istream& operator>>(istream& in, string& s);
}

String.cpp文件

namespace ywc
{const size_t string::npos = -1;void string::reserve(size_t n){if (n > _capacity){//"\0"char* tmp = new char[n + 1];strcpy(tmp, _str);delete[] _str;_str = tmp;_capacity = n;}}void string::push_back(char ch){if (_size == _capacity){reserve(_capacity == 0 ? 4 : 2 * _capacity);}_str[_size++] = ch;_str[_size] = '\0';}string& string::append(const char* str){size_t len = strlen(str);if (len + _size >= _capacity){reserve(len + _size > 2 * _capacity ?len + _size : 2 * _capacity);}strcpy(_str + _size, str);_size += len;return *this;}string& string::operator+=(char ch){push_back(ch);return *this;}string& string::operator+=(const char* str){append(str);return *this;}string& string::insert(size_t pos, const char ch){assert(pos <= _size);if (_size == _capacity){reserve(_capacity = 0 ? 4 : 2 * _capacity);}size_t end = _size + 1;while (end > pos){_str[end] = _str[end - 1];end--;}_str[pos] = ch;_size++;return *this;}string& string::insert(size_t pos, const char* str){assert(pos < _size);size_t len = strlen(str);if (len + _size >= _capacity){reserve(len + _size > 2 * _capacity ? len + _size : 2 * _capacity);}size_t end = len + _size;while (end - len >= pos){_str[end] = _str[end - len];end--;}for (size_t i = 0; i < len; i++){_str[pos + i] = str[i];}_size += len;return *this;}string& string::erease(size_t pos, size_t len){assert(pos < _size);if (len >= _size - pos){_size = pos;_str[pos] = '\0';}else{for (size_t i = pos;i<=_size-len;i++){_str[i] = _str[i + len];}_size -= len;}return *this;}size_t string::find(char ch, size_t pos){assert(pos < _size);for (size_t i = 0; i < _size; i++){if (_str[i] == ch)return i;}return npos;}size_t string::find(const char* str, size_t pos){assert(pos < _size);char* tmp = strstr(_str + pos, str);if (tmp == nullptr)return npos;elsereturn tmp - _str;}string string::substr(size_t pos, size_t len){assert(pos < _size);if (len > _size - pos){len = _size - pos;}string sub;sub.reserve(len);for (size_t i = 0; i < len; i++){sub += _str[pos + i];}return sub;}ostream& operator<<(ostream& out, string& s){for (auto& ch : s){cout << ch;}return out;}istream& operator>>(istream& in, string& s){const size_t N = 256;char buff[N] = { 0 };char ch = 0;ch = in.get();int i = 0;while (ch != ' ' && ch != '\n'){buff[i++] = ch;if (i == N - 1){buff[i] = '\0';s += buff;//尾插i = 0;//重置i}ch = in.get();}if (i > 0)//将剩下的数据尾插{buff[i] = '\0';s += buff;}return in;}
}

好了,我们下期见!

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Kafka+PostgreSql,构建一个总线服务
  • 828华为云征文|部署在线文件管理器 Spacedrive
  • Winform登录实现及工具栏切换
  • Selenium等待机制:理解并应用显式等待与隐式等待,解决页面加载慢的问题
  • electron-vite vue3离线使用monaco-editor
  • 剃(磨)前插齿刀设计计算开发第二步:
  • SIP Servlets学习
  • 打通最后一公里:使用CDN加速GitHub Page的访问
  • Matlab 的.m 文件批量转成py文件
  • 《机器学习by周志华》学习笔记-神经网络-02感知机与多层网络
  • 解密与推广IAB/MRC零售媒体测量指南
  • fedora silverblue
  • 408算法题leetcode--第八天
  • redis的一主二从三哨兵配置
  • 基于Java的SSM(Spring、Spring MVC、MyBatis)框架构建的远程诊断系统
  • C++回声服务器_9-epoll边缘触发模式版本服务器
  • Docker 1.12实践:Docker Service、Stack与分布式应用捆绑包
  • Fabric架构演变之路
  • Linux中的硬链接与软链接
  • node学习系列之简单文件上传
  • 工作踩坑系列——https访问遇到“已阻止载入混合活动内容”
  • 构建工具 - 收藏集 - 掘金
  • 技术:超级实用的电脑小技巧
  • 买一台 iPhone X,还是创建一家未来的独角兽?
  • 使用putty远程连接linux
  • 我有几个粽子,和一个故事
  • 限制Java线程池运行线程以及等待线程数量的策略
  • 一个JAVA程序员成长之路分享
  • kubernetes资源对象--ingress
  • ​ 全球云科技基础设施:亚马逊云科技的海外服务器网络如何演进
  • ​LeetCode解法汇总2583. 二叉树中的第 K 大层和
  • ​总结MySQL 的一些知识点:MySQL 选择数据库​
  • ‌移动管家手机智能控制汽车系统
  • # 达梦数据库知识点
  • #if等命令的学习
  • $.ajax中的eval及dataType
  • (145)光线追踪距离场柔和阴影
  • (2)Java 简介
  • (4)logging(日志模块)
  • (9)目标检测_SSD的原理
  • (DFS + 剪枝)【洛谷P1731】 [NOI1999] 生日蛋糕
  • (Java数据结构)ArrayList
  • (STM32笔记)九、RCC时钟树与时钟 第一部分
  • (二)fiber的基本认识
  • (二)构建dubbo分布式平台-平台功能导图
  • (亲测)设​置​m​y​e​c​l​i​p​s​e​打​开​默​认​工​作​空​间...
  • (四)七种元启发算法(DBO、LO、SWO、COA、LSO、KOA、GRO)求解无人机路径规划MATLAB
  • (一)springboot2.7.6集成activit5.23.0之集成引擎
  • (源码版)2024美国大学生数学建模E题财产保险的可持续模型详解思路+具体代码季节性时序预测SARIMA天气预测建模
  • .net 程序发生了一个不可捕获的异常
  • .net最好用的JSON类Newtonsoft.Json获取多级数据SelectToken
  • /usr/lib/mysql/plugin权限_给数据库增加密码策略遇到的权限问题
  • [Algorithm][动态规划][01背包问题][目标和][最后一块石头的重量Ⅱ]详细讲解
  • [Android Pro] listView和GridView的item设置的高度和宽度不起作用
  • [C#][DevPress]事件委托的使用