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

c++ string类 +底层模拟实现

提醒:

本片博客只是小编的听课笔记,介意勿看。

基础

包含在头文件<string>,才能使用string类似函数接口。

string常见构造类

string s1; 
cin>>s1;//无参构造
string s2(s1);//拷贝构造
string s1("jfksa");//传参构造

三种遍历方式

//三种遍历方式
//s.begin()返回第一个字符
//s.end();返回最后一个字符的下一个位置(\0位置)
//一operator【】
for (int i = 0; i < s2.size(); i++) {
	cout << s2[i];
}
cout << endl;
//二.迭代器iterator
string::iterator it = s2.begin();//it类似于指针,但本质可能和是运算符重载
while (it != s2.end()) {
	cout << *it;//*it类似于解引用。本质也像是运算符重载
	it++;
}
cout << endl;
//三。范围for进行遍历
//范围for进行遍历
string s3("llpphh");
for (auto ch : s3) {
	cout << ch << " ";
}
cout << endl;

迭代器和范围for的去区别

两则底层逻辑相同,但是对于迭代器来讲可以在迭代器中修改变量值(因为底层类似指针可以直接修改对应地址的·1值),而对于范围for来讲,(auto ch: s2)相当于是一个拷贝,修改ch的值并不能修改实参的值,所以需要用引用(auto& ch: s2)才能修改变量的值。

auto

使用价值:方便类型推导

string::ioterator it=    //变量名太长
auto it =    ;  //简化

typeid(变量名).name()//判断变量类型

string迭代器

iterator //正向

const_iterator //const

reverse_iterator //反向

const_reverse_iterator //const 反向

对应案列如下

string s4("hello world");
//正向
string::iterator it1 = s4.begin();
while (it1 != s4.end()) {
	cout << *it1;
	it1++;
}
cout << endl;
//反向迭代器
string::reverse_iterator rit = s4.rbegin();
while (rit != s4.rend()) {
	cout << *rit;
	rit++;
}
cout << endl;
const string s5("hello world");
//const迭代器
string::const_iterator it2 = s5.begin();
while (it2 != s5.end()) {
	cout << *it2;
	it2++;
}
cout << endl;
//const反向迭代器
string::const_reverse_iterator it3 = s5.rbegin();
while (it3 != s5.rend()) {
	cout << *it3;
	it3++;
}
cout << endl;

string 容器

size()/length()

//size获取字符长度
string s2("lvpanhao");
cout << s2.size() << endl;//经常用
cout << s2.length() << endl;//不具有通用性

capacity()扩容

s.reverse(n)//提前开n个空间

s.clear()//清除字符串/不清楚容量

s.push_back('x');//尾插字符
s.append("aaaaaaaa");//尾插字符串

insert/头插

s.insert('x'/"hujkf");//可以是字符也可以是字符串

erase//指定位置删除字符

s.erase(pos ,n)//pos位置删除n个字符
s.erase(s.begin());//迭代器版本头删

replace();//替换

replace(pos,n,'%%');//pos的n个位置替换成%%

substr//构建子串、

string s5("lvpanhao");
cout << s5.substr(2, 3) << endl;//下表为2 长度为3的子串

find//查找指定字符/指定字符串

int pos=s.find(' ');//返回找到字符的下标
//把所有空格替换为%
//替换所有空格为%
string s4("hello world I am Lihua");
int pos = s4.find(' ');
while (pos != string::npos) {
	s4.replace(pos, 1, "%%");
	pos = s4.find(' ');//每次从头开始找替换为int pod=s.find(' ',pos);//从某个位置开始找字符
}
cout << s4 << endl;

rfind/倒着找

//利用场景
//倒着找文件后缀方法
int pos1 = s6.rfind('.');
cout << s6.substr(pos1) << endl;
string s7("test.cpp.zip");
int pos2 = s7.rfind('.');
cout << s7.substr(pos2) << endl;

ind_first_of("abcd")//查找abcd所在位置

find_last_of("abcd")//倒着找查找不是abcd的全替换

string s8("hello world i love you");
//把aeiou字符改为*
size_t pos3 = s8.find_first_of("aeiou");
while (pos3 != string::npos) {
	s8.replace(pos3,1,"*");
	pos3 = s8.find_first_of("aeiou",pos3+1);
}
cout << s8 << endl;

getline()遇到换行才终止

string s1;
getline(cin,s1,)
//自己加终止条件
getLine(cin,s1,‘*‘);//默认遇到*终止

c_str()

相当于一个字符一个字符读取字符串,遇到,‘\0’会终止读取。

字符串匹配

strstr算法

strstr(const char* str1,const char* str2);

str2字串/str1主串

字串str2返回str1中的第一个位置字符

优化拷贝构造(赋值重载)

传统拷贝构造(赋值重载)

//拷贝构造
string& string(const string& s1){
    //必须先自己申请空间
    _str=new char[n];
    strcpy(_str,s1._str);
    _size=s1.size;
    _capacity=s1._capacity;
}
//赋值重载
string& string(const string& s1){
    //必须先自己申请空间
    delete[] _str;
    _str=new char[n];
    strcpy(_str,s1._str);
    _size=s1.size;
    _capacity=s1._capacity;
}

现代拷贝构造

//利用交换函数
string& string(const string& s1){
    string tem(s1);
    (this)->swap(tem);
}

最简单拷贝构造/赋值重载

string& string(string s1){
  //s1是局部变量直接进行交换
   swap(s1);//this->swap(s1);
}

写时拷贝

对于拷贝构造,对自定义类型完成神拷贝,浅拷贝(一个字节一个字节拷贝)并不能满足,原因如下

1.析构两次

2.修改内容时修改两个指针指向的内容

对于写时拷贝只试用满足原因1,并不能满足条件2(自己进行扩容规深拷贝)

string类模拟实现

string.h
#pragma once
#include<iostream>
#include<assert.h>
using namespace std;
namespace lph {

	class string {
	public:
		typedef char* iterator;
		重载无参函数
		//string()
		//	:_str(nullptr)
		//	,_size(0)
		//	,_capacity(0)
		//{}
		带参数构造
		//string(const char* str) {
		//	_size = strlen(str);
		//	_capacity = _size;
		//	_str = new char[_size + 1];
		//	strcpy(_str, str);
		//}
		//迭代器begin使用
		iterator begin() {
			return _str;
		}
		//end使用
		iterator end() {
			return _str + _size;
		}

		// 全缺省
		string(const char* str = "") {
			_size = strlen(str);
			_capacity = _size;
			_str = new char[_capacity + 1];
			strcpy(_str, str);
		}
		//输出
		const char* c_str() {
			return _str;
		}
		//获取size大小
		size_t size() {
			return _size;
		}
		//获取总空间大小
		size_t capacity() {
			return _capacity;
		}
		//循环遍历
		char& operator[](size_t pos) {
			assert(pos < _size);
			return _str[pos];
		}
		//拷贝构造
		string(const string& s) {
			_str = new char[s._capacity+1];
			strcpy(_str, s._str);
			_size = s._size;
			_capacity = s._capacity;
		}
		//赋值重载
		//s1=s2
		string& operator=(const string& s) {
	 		delete[] _str;
			_str = new char[s._capacity + 1];
			strcpy(_str, s._str);
			_size = s._size;
			_capacity = s._capacity;
			return *this;
		}
		//扩容
		void reserve(size_t n);
		//三个尾插
		void push_back(char ch);
		void append(const char* str);
		string& operator+=(char ch);
		string& operator+=(const char* str);
		~string() {
			delete[] _str;
			_size = _capacity = 0;
		}
		//中间插入
		void insert(size_t pos, char ch);
		void insert(size_t pos, const char* str);
		//删除字符
		void erase(size_t pos, size_t len);
		//查找指定字符
		size_t find(char ch, size_t pos = 0);
		//查找指定字串
		size_t find(const char* str, size_t pos);
		//从某个位置获取多长的字符 
		string substr(size_t pos, size_t len);
	private:
		char* _str;
		size_t _size;
		size_t _capacity;
	};
	void test1();
	void test2();
	void test3();
	//比较函数实现
	bool operator<(string& s1, string& s2);
	bool operator<=(string& s1, string& s2);
	bool operator>(string& s1, string& s2);
	bool operator>=(string& s1, string& s2);
	bool operator==(string& s1, string& s2);
	bool operator!=( string& s1,  string& s2);
	
}
string.cpp

#define _CRT_SECURE_NO_WARNINGS 1
#include"string.h"
namespace lph {
	void test1() {
		cout << "::test1::" << endl;

		string s1;
		string s2("hello world");
		cout << s1.c_str() << endl;
		cout << s2.c_str() << endl;
		cout << s2.size() << endl;
		cout << s2.capacity() << endl;
		cout << s2[6] << endl;
		//普通遍历
		for (size_t i = 0; i < s2.size(); i++) {
			cout << s2[i];
		}
		cout << endl;
		//for遍历
		for (auto ch : s2) {
			cout << ch;
		}
		cout << endl;
		//迭代器遍历
		string::iterator it = s2.begin();
		while (it != s2.end()) {
			cout << *it;
			it++;
		}
		cout << endl;
		cout << endl;
		cout << endl;
		cout << endl;
	}
	void test2() {
		cout << "::test2::" << endl;
		string s1("hello world");
		s1.push_back('x');
		cout << s1.c_str() << endl;
		s1 += 'p';
		cout << s1.c_str() <<endl;
		string s2("hello world");
		s2 += " lvpanhao";
		cout << s2.c_str() <<endl;
		//头插
		cout << "::test::" << endl;
		string s3("hello world");
		s3.insert(5, 'x');
		cout << s3.c_str() <<endl;
		string s4("hello world");
		s4.insert(5, "@@@@@");
		cout << s4.c_str() << endl;
		cout << "::test::" << endl;
		string s5("hello world");
		s5.erase(5, 10);
		cout << s5.c_str() << endl;
		string s6("hello world");
		s6.erase(5, 3);
		cout << s6.c_str() << endl;
	}
	void test3() {
		string s1("hello world");
		cout << s1.find('o',0) << endl;
		string s2("hello lvpanhao world");
		string s= s2.substr(6,8);
		cout << s.c_str() << endl;
		string copy(s2);
		cout << copy.c_str() << endl;
		string s3=(copy = s);
		cout << s3.c_str() << endl;
		string s4("hello");
		string s5("woshi");
		cout << (s4 < s5) << endl;
		cout << (s4 == s5) << endl;
		cout << (s4 > s5) << endl;
		//拷贝构造
		string s6("lvpanhao");
		string s7("nihao");
		string s8(s6);
		cout << s8.c_str() << endl;
		//赋值重载
		s6=s7;
		cout << s6.c_str() << endl;
	}
	void string::reserve(size_t n) {
		if (n > _capacity) {
			char* tem = new char[n + 1];
			strcpy(tem, _str);
			delete[] _str;
			_str = tem;
			_capacity = n;
		}
	}
	void string::push_back(char ch) {
		//扩容
		if (_size == _capacity) {
			reserve(_capacity == 0 ? 4 : 2 * _capacity);
		}
		_str[_size] = ch;
		_size++;
		_str[_size] = '\0';
	}
	string& string::operator+=(char ch) {
		push_back(ch);
		return *this;
	}
	void 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;
	}
	string& string::operator+=(const char* str) {
		append(str);
		return *this;
	}
	//中间插入
	void string::insert(size_t pos, char ch) {
		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+=1;
	}
	void string::insert(size_t pos, const char* str) {
		assert(pos < _size);
		size_t len = strlen(str);
		if (_size + len > _capacity) {
			//扩容
			reserve(_size + len > 2 * _capacity ? _size + len : 2 * _capacity);
		}
		size_t end = _size + len;
		while (end >= pos + len) {
			_str[end] = _str[end - len];
			end--;
		}
		for (size_t i = 0; i < len; i++) {
			_str[pos++] = str[i];
		}
		_size += len;
	}
	//删除字符
	void string::erase(size_t pos, size_t len) {
		if (len > _size - pos) {
			_str[pos] = '\0';
			_size = pos;
		}
		else {
			for (size_t i = pos + len; i <= _size; i++) {
				_str[pos++] = _str[i];
			}
			_size -= len;
		}
	}
	//查找指定字符
	size_t string::find(char ch, size_t pos) {
		for (size_t i = pos; i < _size; i++) {
			if (ch == _str[i]) {
				return i;
			}
		}
		return -1;
	}
	//查找指定字串
	size_t string::find(const char* str, size_t pos) {
		assert(pos < _size);
		char* ptr = strstr(_str+pos, str);
		if (ptr == nullptr) {
			return -1;
		}
		else {
			return ptr - _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;
	}
   //比较函数实现
   bool operator<(string& s1,  string& s2) {
	   return strcmp(s1.c_str(), s2.c_str())<0;
   }
   bool operator<=( string& s1,  string& s2) {
	   return (s1 < s2) || (s1 == s2);
   }
   bool operator>( string& s1,string& s2) {
	   return !(s1 <= s2);
   }
   bool operator>=(string& s1, string& s2) {
	   return !(s1 < s2);
   }
   bool operator==(string& s1,string& s2) {
	   return strcmp(s1.c_str(), s2.c_str()) == 0;
   }
   bool operator!=(string& s1,string& s2) {
	   return !(s1 == s2);
   }
   //自定义插入
   ostream& operator<<(ostream& out, string& s) {
	   for (auto ch : s) {
		   out << ch;
	   }
	   return out;
   }
   istream& operator>>(istream& ci, string& s) {
	   char ch;
	   //ci >> ch;//遇到空格或换行会默认未字符串
	   ch = ci.get();
	   while (ch != ' ' || ch != '\0') {
		   s += ch;
		   //ci >> ch;
		   ch = ci.get();
	   }
	   return ci;
   }
}
#define _CRT_SECURE_NO_WARNINGS 1
#include"string.h"
	int main() {
		lph::test1();
		lph::test2();
		lph::test3();
		return 0;
	}


http://www.kler.cn/a/533092.html

相关文章:

  • 如何生成强密码:提高网络安全性的全面指南
  • DeepSeekMoE:迈向混合专家语言模型的终极专业化
  • 2000-2020年 儒家文化-儒学中心数据-社科数据
  • Rust中使用ORM框架diesel报错问题
  • 电路研究9.2.8——合宙Air780EP中IP 应用相关命令使用方法研究
  • gdb 调试多进程中多线程的方法
  • 《VSCode 与 QT:强强联合的开发利器》
  • 解决 LeetCode 922 题:按奇偶排序数组 II
  • Linux 传输层协议 UDP 和 TCP
  • FPM(Effing Package Management)安装与使用指南
  • B-树:解锁大数据存储和与快速存储的密码
  • 基于JavaWeb开发的Java+Jsp+SpringMVC漫威手办商城系统设计和实现
  • 1分钟基于腾讯云TI平台搭建DeepSeek大模型
  • 2025-2-3-sklearn学习(50) (51) 完结篇 零落成泥碾作尘,只有香如故。
  • Vite:现代前端开发的利器
  • Spring Security(maven项目) 3.0.3.0版本
  • 接口测试通用测试用例
  • 深度剖析八大排序算法
  • 【MySQL — 数据库基础】深入解析MySQL的约束操作
  • 如何获取sql数据中时间的月份、年份(类型为date)
  • 【大数据技术】本机PyCharm远程连接虚拟机Python
  • 【电脑系统】电脑突然(蓝屏)卡死发出刺耳声音
  • 第 11 课 Python 多线程
  • idea中git的简单使用
  • 基于RK3588/RK3576+MCU STM32+AI的储能电站电池簇管理系统设计与实现
  • OpenAI的第二个AI Agent:Deep Research完全解读!