string类的认识

ops/2024/11/25 13:39:41/

一、初始string类

        在 C++ 中,std::string是标准库提供的用于处理字符串的类。它提供了比 C 风格字符串(以'\0'结尾的字符数组)更方便、更安全的字符串处理方式。

        要使用std::string,需要包含<string>头文件。并且,std::string位于std命名空间中。可以通过using namespace std;来引入整个std命名空间,不过这种方式可能会导致命名冲突,更推荐的是使用std::string这种完整的限定名称。

二、常用接口  

1.string类对象的常见构造         

string() -- 构造空的string对象,即一个空字符串                            --无参构造

string(const char* s) -- 用C->string来构造string对象                     --带参构造

string(size_t n,char c) -- 构造并初始化一个string对象,含n个c    --带参构造

string(const string& s) -- 拷贝构造                                                 --拷贝构造

2.string类对象的容量操作

size() -- 返回字符串有效长度

length()  -- 返回字符串有效字符长度

capacity() -- 返回总空间大小

empty()  -- 判空

clear() -- 清空有效字符

reserve() -- 为字符串预留空间

resize() -- 将有效字符的个数改成n个,多出的空间用字符c填充

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

operator[]() -- 返回pos位置的字符,const string对象调用

begin + end -- string的迭代器,分别获取第一个字符和以后一个字符的下一个位置

rbegin + rend -- 反向迭代器,分别返回最后一个字符和第一个字符之前的位置

范围for -- C++11支持更简洁的范围for的新遍历方式

4. string类对象的修改操作

push_back() -- 尾插字符

append() -- 字符串末尾追加字符串

operator+=() -- 字符串末尾追加字符串

c_str() -- 返回c语言格式字符串

find() + npos -- 从pos位置开始往后找目标字符,返回其位置

rfind() -- 从pos位置往前开始找目标字符,返回其位置

substr() -- 在字符串的pos位置开始,截取n个字符,将其返回

5.string类非成员函数

operator+() -- 返回一个新构造的字符串对象,其值是 lhs 中的字符后跟 rhs 中的字符的串联。

operator>>() -- 输入运算符重载

operator<<() -- 输出运算符重载

getline() -- 获取一行字符串

relational operators() -- 大小比较

三、string的常见问题

         浅拷贝:也称位拷贝,编译器只是将对象中的值拷贝过来。如果对象中管理资源,最后就会导致多个对象共享同一份资源,当一个对象销毁时就会将该资源释放掉,而此时另一些对象不知道该资源已经被释放,以为还有效,所以当继续对资源进项操作时,就会发生发生了访问违规。
        在string中如果没有显式定义其拷贝构造和赋值运算符重载,编译器会调用默认,而默认是浅拷贝,可能会导致多个对象指向同一块资源,最后析构释放时,致使同一块空间被多次释放而引起崩溃。
        
        拷贝构造和赋值重载的现代写法:
        
class string
{
public://传统写法string(const string& s){_str = new char[s._capacity + 1];_capacity = s._capacity;_size = s._size;strcpy(_str, s._str);}//现代写法string(const string& s){string tmp(s);Swap(tmp);}//传统写法string& operator=(const string& s){if (this != &s){delete[] _str;_str = new char[s._capacity + 1];_capacity = s._capacity;_size = s._size;strcpy(_str, s._str);}}//现代写法string& operator=(string s){Swap(s);return *this;}void Swap(string& s){std::swap(_str, s._str);std::swap(_size, s._size);std::swap(_capacity, s._capacity);}private:char* _str;int _size;int _capacity;
};

四、string的模拟实现

#pragma once
#include<iostream>
#include<string>
#include<assert.h>
using namespace std;namespace ts
{class string{public:typedef char* iterator;typedef const char* const_iterator;//迭代器iterator begin(){return _str;}//返回最后一个数据的下一个iterator end(){return _str + _size;//0 + 3 = 3}const_iterator begin() const{return _str;}const_iterator end() const{return _str + _size;//0 + 3 = 3}//初始化列表初始化/*string():_str(new char[1]{'\0'}),_size(0),_capacity(0){}*/// 短小频繁调用的函数,可以直接定义到类里面,默认是inlinestring(const char* str = ""){_size = strlen(str);_capacity = _size;_str = new char[_capacity + 1];strcpy(_str, str);}// 深拷贝问题// 传统写法-- 拷贝构造// s2(s1)string(const string& s){_str = new char[s._capacity + 1];strcpy(_str, s._str);_size = s._size;_capacity = s._capacity;}现代写法//string(const string& s)//{//	string tmp(s._str);//	Swap(tmp);//Swap(*this,tmp)//}void Swap( string& s){std::swap(_str, s._str);std::swap(_size, s._size);std::swap(_capacity, s._capacity);}// s2 = s1// s1 = s1--传统写法string& operator=(const string& s){if (this != &s){delete[]_str;_str = new char[s._capacity];strcpy(_str, s._str);_size = s._size;_capacity = s._capacity;}return *this;}//现代写法--及其简洁,并且效率相同/*string& operator=(string tmp){Swap(tmp);return *this;}*/~string(){delete[]_str;_str = nullptr;_size = _capacity = 0;}const char* c_str() const{return _str;}//清除原数据但不改变空间大小void clear(){_str[0] = '\0';_size = 0;}//返回数据数目size_t size() const{return _size;}//返回空间大小size_t capacity() const{return _capacity;}//类似取地址操作char& operator[](size_t pos){assert(pos < _size);return _str[pos];}const char& operator[](size_t pos) const{assert(pos < _size);return _str[pos];}void reserve(size_t n);void push_back(char ch);void append(const char* str);string& operator+=(char ch);string& operator+=(const char* str);void insert(size_t pos, char ch);void insert(size_t pos, const char* str);void erase(size_t pos, size_t len = npos);size_t find(char ch, size_t pos = 0);size_t find(const char* str, size_t pos = 0);string substr(size_t pos = 0, size_t len = npos);private://char _buff[16];char* _str;size_t _size;size_t _capacity;//static const size_t npos = -1;static const size_t npos;/*static const int N = 10;int buff[N];*/};bool operator<(const string& s1, const string& s2);bool operator<=(const string& s1, const string& s2);bool operator>(const string& s1, const string& s2);bool operator>=(const string& s1, const string& s2);bool operator==(const string& s1, const string& s2);bool operator!=(const string& s1, const string& s2);ostream& operator<<(ostream& out, const string& s);istream& operator>>(istream& in, string& s);
}

        

#include"string.h"namespace ts
{//npos的初始化不能在头文件中定义//否则在后面每次链接时,会发生重复定义const size_t string::npos = -1;//保留空间void string::reserve(size_t n){if (n > _capacity){char* tmp = new char[n + 1];strcmp(tmp, _str);delete[]_str;_str = tmp;_capacity = n;}}//尾插void string::push_back(char ch){//是否需要扩容if (_size == _capacity){reserve(_capacity == 0 ? 4 : _capacity * 2);}_str[_size] = ch;++_size;//注意末尾\0的添加_str[_size] = '\0';}//尾插字符串void string::append(const char* str){size_t len = strlen(str);if (_size + len > _capacity){reserve(_size + len > _capacity * 2 ? _size + len : _capacity * 2);}strcpy(_str + _size, str);_size += len;}//添加字符--加等一个字符string& string::operator+=(char ch){push_back(ch);return *this;}string& string::operator+=(const char* str){append(str);return *this;}//在指定位置插入字符void string::insert(size_t pos, char ch){assert(pos <= _size);//挪动的时候别忘记了末尾的\0int end = _size + 1;while (end > pos){_str[end] = _str[end - 1];--end;}_str[end] = ch;++_size;}//在指定位置插入字符串void string::insert(size_t pos, const char* str){assert(pos<= _size);size_t len = strlen(str);if (_size + len > _capacity){//扩容// 大于2倍,需要多少开多少,小于2倍按2倍扩reserve(_size + len > 2 * _capacity ? _size + len : 2 * _capacity);}//往后挪动数据size_t end = _size + len;while (end > pos + len - 1){_str[end] = _str[end - 1];--end;}//填充字符串for (size_t i = 0; i < len; i++){_str[pos + i] = str[i];}_size += len;}//从指定位置开始,删除pos个字符,未指定长度则默认为nopsvoid string::erase(size_t pos, size_t len){assert(pos < _size);if (_size - pos <= len){_str[pos] = '\0';_size = pos;}else{for (size_t i = pos + len; i < _size; ++i){_str[i - len] = _str[i];}_size -= len;}}size_t string::find(char ch, size_t pos){assert(pos < _size);for (size_t i = pos; i < _size; i++){if (_str[i] == ch){return i;}}return npos;}size_t string::find(const char* str, size_t pos){assert(pos < _size);//strstr--找出第二个字符串首次出现在第一个字符串中的位置const char* ptr = strstr(_str + pos, str);if (ptr == nullptr){return npos;}else{return ptr - _str;}}//读取字符串在pos位置的len个字符string string::substr(size_t pos, size_t len){assert(pos < _size);// len大于剩余字符长度,更新一下lenif (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;}bool operator<(const string& s1, const string& s2){//strcmp -- 第一个字符串大于第二个 返回>0,小于返回<0等于返回=return strcmp(s1.c_str(), s2.c_str()) < 0;}bool operator<=(const string& s1, const string& s2){return s1 < s2 || s1 == s2;}bool operator>(const string& s1, const string& s2){return !(s1 <= s2);}bool operator>=(const string& s1, const string& s2){return !(s1 < s2);}bool operator==(const string& s1, const string& s2){return strcmp(s1.c_str(), s2.c_str()) == 0;}bool operator!=(const string& s1, const string& s2){return !(s1 == s2);}ostream& operator<<(ostream& out, const string& s){out << s.c_str();/*for (auto e : s){out << e;}*/return out;}istream& operator>>(istream& in, string& s){//清除数据s.clear();const int N = 256;char buff[N];int i = 0;char ch = in.get();while (ch != ' ' && ch != '\n'){buff[i++];//避免频繁开辟空间if (i == N - 1){buff[i] = '\0';s += buff;i = 0;}}if (i > 0){buff[i] = '\0';s += buff;}return in;}
}


http://www.ppmy.cn/ops/136581.html

相关文章

Vulnhub靶场 Jangow: 1.0.1 练习

目录 0x00 准备0x01 主机信息收集0x02 站点信息收集0x03 漏洞查找与利用1. 命令执行2. 反弹shell3. 提权4. 补充4.1 其他思路4.2 问题 0x04 总结 0x00 准备 下载链接&#xff1a;https://download.vulnhub.com/jangow/jangow-01-1.0.1.ova 介绍&#xff1a; Difficulty: easy…

[Unity Demo]从零开始制作空洞骑士Hollow Knight第二十集:制作专门渲染HUD的相机HUD Camera和画布HUD Canvas

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、制作HUD Camera以及让两个相机同时渲染屏幕二、制作HUD Canvas 1.制作法力条Soul Orb引入库2.制作生命条Health读入数据3.制作吉欧统计数Geo Counter4.制作…

【jvm】从字节码角度看待对象创建流程

目录 1. 分配内存空间2. 初始化内存空间为零值3. 设置对象头4. 调用构造函数初始化对象5. 示例代码6. 字节码指令解析 1. 分配内存空间 1.在Java中&#xff0c;对象存储在堆&#xff08;Heap&#xff09;内存中。2.当创建一个新对象时&#xff0c;JVM首先需要为对象分配一块内…

ONNX 输入batch修改

ONNX 输入batch修改 导出的onnx模型分为静态和动态输入两种&#xff0c;但一般用户会在导出后进行onnxsim操作&#xff0c;导致某些非全卷积的模型修改batch失败&#xff0c;比如transformer类其中reshape的attr属性会固定&#xff0c;修改相当麻烦&#xff0c;需要从源头重新…

Git命令使用与原理详解

1.仓库 # 在当前目录新建一个Git代码库 $ git init ​ # 新建一个目录&#xff0c;将其初始化为Git代码库 $ git init [project-name] ​ # 下载一个项目和它的整个代码历史 $ git clone [url]2.配置 # 显示当前的Git配置 $ git config --list ​ # 编辑Git配置文件 $ git co…

UE5 slate BlankProgram独立程序系列

源码版Engine\Source\Programs\中copy BlankProgram文件夹&#xff0c;重命名为ASlateLearning&#xff0c;修改所有文件命名及内部名称。 ASlateLearning.Target.cs // Copyright Epic Games, Inc. All Rights Reserved.using UnrealBuildTool; using System.Collections.Ge…

Java的包装类及其缓存机制

Java的包装类及其缓存机制 ​ Java 的包装类&#xff08;Wrapper Classes&#xff09;是为每种基本数据类型提供的对象表示。基本数据类型&#xff08;如 int、double 等&#xff09;是非对象类型&#xff0c;而包装类为它们提供了对应的对象版本&#xff0c;以便可以在需要对…

手撕一个阻塞队列

目录 手撕一个阻塞队列代码讲解 手撕一个阻塞队列 要手撕一个阻塞队列&#xff1a;就要实现一个普通的队列&#xff0c;加上阻塞&#xff0c;加上锁 代码 class MyBlockingQueue{private String[] elemsnull;private int tail0;private int head0;private int size0;private…