前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >今天你学C++了吗?——string底层总代码

今天你学C++了吗?——string底层总代码

作者头像
用户11352420
发布2025-03-10 09:13:50
发布2025-03-10 09:13:50
12000
代码可运行
举报
文章被收录于专栏:编程学习编程学习
运行总次数:0
代码可运行

前面两篇博客我们介绍了string类接口以及实现~std::string是C++标准库中的字符串类,提供丰富的成员函数用于字符串操作,如构造、访问、修改、比较、查找子串等。它支持通过索引访问字符,迭代器遍历,以及高效的内存管理,是C++中处理字符串的首选工具~

string.h

代码语言:javascript
代码运行次数:0
运行
复制
#pragma once
#include<iostream>
#include<string.h>
#include<assert.h>
using namespace std;
namespace Xiaodu
{
	class my_string//与库里面的进行区分
	{
	private:
		char* _str;//字符指针
		size_t _size;//统计长度
		size_t _capacity;//统计最大容量
		const static size_t _npos;//静态常量,用于表示一个无效的位置或未找到的位置
	public:
		//成员函数
		//构造
		my_string(const char* str);
		my_string(size_t n, char ch);
		//析构
		~my_string();
		//默认构造
		my_string();
		void clear()
		{
			_str[0] = '\0';
			_size = _capacity = 0;
		}
		//友元声明
		//<<运算符重载
		friend ostream& operator<<(ostream& out, my_string& s);
		//>>运算符重载
		friend istream& operator>>(istream& in, my_string& s);
		//拷贝构造
		my_string(const my_string& s);
		//赋值运算符重载
		my_string& operator=(my_string& s);
		//reserve
		void reserve(size_t n);
		//push_back
		void push_back(char ch);
		//append
		void append(const char* s);
		//+=一个字符
		my_string& operator+=(char c);
		//+=一个字符串
		my_string& operator+=(const char* c);
		//insert字符
		void insert(size_t pos, size_t n, char c);
		//insert字符串
		void insert(size_t pos, const char* s);
		//erase
		void erase(size_t pos, size_t n);
		//find字符
		size_t find(char c, size_t pos = 0);//声明给默认参数!!!
		//find字符串
		size_t find(const char* s, size_t pos = 0);
		//substr
		my_string substr(size_t pos = 0, size_t len = _npos);
		//==
		bool operator==(const my_string& s)const;
		//!=
		bool operator!=(const my_string& s)const;
		//<
		bool operator<(const my_string& s)const;
		//<=
		bool operator<=(const my_string& s)const;
		//>
		bool operator>(const my_string& s)const;
		//>=
		bool operator>=(const my_string& s)const;
	};
	//<<运算符重载
	ostream& operator<<(ostream& out, my_string& s);
	//>>运算符重载
	istream& operator>>(istream& in, my_string& s);
	//getline
	istream& getline(istream& in, my_string& s, char end = '\n');//可以自己指定获取字符串结束的标志
}

string.cpp

代码语言:javascript
代码运行次数:0
运行
复制
#include"string.h"//记得包含头文件
namespace Xiaodu
{
	const  size_t my_string::_npos = -1;
	//构造
	my_string::my_string(const char* str)//常量字符串
		:_size(strlen(str))//使用strlen求有效长度来初始化
	{
		//使用已经初始化的_size来初始化剩下的
		_capacity = _size;
		_str = new char[_size + 1];
		strcpy(_str, str);
	}
	my_string::my_string(size_t n, char ch)
		:_size(n),_str(new char[n+1]),_capacity(n)
	{
		for (size_t i = 0; i < n; i++)
		{
			_str[i] = ch;
		}
		_str[_size] = '\0';//结束标志\0
	}
	//默认构造
	my_string::my_string()
	{
		_str = new char[1];
		_str[0] = '\0';//一个字符保存'\0'
		_size = 0;
		_capacity = 0;
	}

	//析构
	my_string::~my_string()
	{
		delete _str;//new,delete匹配使用
		_str = nullptr;
		_size = 0;
		_capacity = 0;
	}
	//拷贝构造
	//s2(s1)
	//传统写法
	/*my_string::my_string(const my_string& s)
	{
		_size = s._size;
		_capacity = s._capacity;
		_str = new char[_capacity + 1];
		strcpy(_str, s._str);
	}*/

	//现代写法
	my_string::my_string(const my_string& s)
	{
		my_string tmp(s._str);//让构造帮我们写
		swap(_str, tmp._str);
		swap(_size, tmp._size);
		swap(_capacity, tmp._capacity);
	}
	//赋值运算符重载
	//my_string::operator=——这样指定类域
	//s4=s3
	my_string& my_string::operator=(my_string& s)
	{
		//判断是不是自己给自己赋值
		if (this != &s)
		{
			delete _str;//释放原来的,重新开辟空间
			_str = new char[s._capacity + 1];
			strcpy(_str, s._str);
			_size = s._size;
			_capacity = s._capacity;
		}
		return *this;
	}
	void my_string::reserve(size_t n)
	{
		if (n > _capacity)//修改容量比原来的大就进行扩容
		{
			char* tmp = new char[n + 1];
			//创建一个中间指针变量修改容量
			strcpy(tmp, _str);
			delete _str;
			_str = tmp;
			_capacity = n;
		}
	}
	void my_string::push_back(char ch)
	{
		//判断容量是否足够
		if (_capacity == _size)//容量不够进行扩容
		{
			//这里就可以使用reserve进行代码复用
			reserve(_capacity == 0 ? 4 : _capacity * 2);
		}
		_str[_size++]=ch;//插入字符后长度增加
		_str[_size] = '\0';
	}
	void my_string::append(const char* s)
	{
		//求出插入字符串长度
		size_t l = strlen(s);
		//容量不够进行扩容
		if (_size + l > _capacity)
		{
			//默认两倍扩容,还是不够就按需扩容
			size_t newcapacity = _capacity * 2;
			if (_size + l > newcapacity)
			{
				newcapacity = _size + l;
			}
			//1.自己重新写
			char* tmp = new char[newcapacity + 1];//容量记得+1,需要一个字符串结束标志
			strcpy(tmp, _str);
			delete _str;
			_str = tmp;
			_capacity = _size + l;
			//代码复用
			//reserve(newcapacity);
		}
		//拷贝剩下的
		strcpy(_str + _size, s);
		//_size增加
		_size += l;
	}
	//+=一个字符
	my_string& my_string::operator+=(char c)
	{
		push_back(c);
		return *this;
	}
	//返回引用,减少拷贝
	//+=一个字符串
	my_string& my_string::operator+=(const char* c)
	{
		append(c);
		return *this;
	}
	//insert字符
	void my_string::insert(size_t pos, size_t n, char c)
	{
		//判断插入位置和插入个数是否合法
		assert(pos < _size);
		assert(n > 0);
		//判断容量是否足够
		//不够进行扩容
		if (_size + n > _capacity)
		{
			//默认两倍扩容,还是不够就按需扩容
			size_t newcapacity = _capacity * 2;
			if (_size + n > newcapacity)
			{
				newcapacity = _size + n;
			}
			//代码复用
			reserve(newcapacity);
		}
		//移动后面的字符
		size_t end = _size + n - 1;
		//从后面开始移动,避免覆盖
		while (end > pos + n - 1)
		{
			_str[end] = _str[end - n];
			end--;
		}
		//插入字符
		for (size_t i = pos; i < pos + n; i++)
		{
			_str[i] = c;
		}
		_size += n;
		//字符串末尾置为'\0'
		_str[_size] = '\0';
	}
	//insert字符串
	//void my_string::insert(size_t pos, const char* s)
	//{
	//	//方法一:重新写
	//	//判断插入位置和插入个数是否合法
	//	size_t n = strlen(s);
	//	assert(pos < _size);
	//	assert(n);
	//	//判断容量是否足够
	//	//不够进行扩容
	//	if (_size + n > _capacity)
	//	{
	//		//默认两倍扩容,还是不够就按需扩容
	//		size_t newcapacity = _capacity * 2;
	//		if (_size + n > newcapacity)
	//		{
	//			newcapacity = _size + n;
	//		}
	//		//代码复用
	//		reserve(newcapacity);
	//	}
	//	//移动后面的字符
	//	size_t end = _size + n - 1;
	//	//从后面开始移动,避免覆盖
	//	while (end > pos + n - 1)
	//	{
	//		_str[end] = _str[end - n];
	//		end--;
	//	}
	//	//插入字符串里面的字符
	//	for (size_t i = pos; i < pos + n; i++)
	//	{
	//		_str[i] = s[i - pos];
	//	}
	//	_size += n;
	//	//字符串末尾置为'\0'
	//	_str[_size] = '\0';
	//}
	void my_string::insert(size_t pos, const char* s)
	{
		//方法二:代码复用
		size_t n = strlen(s);
		//先占位置,再重新赋值
		insert(pos, n, 'x');
		for (size_t i = 0; i < n; i++)
		{
			_str[pos + i] = s[i];
		}
	}
	//erase
	void my_string::erase(size_t pos, size_t n)
	{
		//判断删除位置
		if (pos + n >= _size)
			//也就是后面的全部删除
		{
			_str[pos] = '\0';
			_size -= n;
		}
		else
			//删除直接进行覆盖就好了
		{
			//把后面的字符向前面移动
			size_t begin = pos + n;
			while (begin < _size)
			{
				_str[begin - n] = _str[begin];
				begin++;
			}
			_size -= n;
			_str[_size] = '\0';
		}
	}
	//find字符
	size_t my_string::find(char c,size_t pos)
		//默认从开头开始找
	{
		//遍历查找
		size_t n = strlen(_str);
		for (size_t i = pos; i < n; i++)
		{
			if (_str[i] == c)
			{
				//找到了返回下标
				return i;
			}
		}
		//找不到返回_npos
		return _npos;
	}
	//find字符串
	size_t my_string::find(const char* s, size_t pos)
	{
		const char* p = strstr(_str + pos, s);//从指定位置开始查找子字符串
		if (p == nullptr)//没有找到,返回_npos
		{
			return _npos;
		}
		else//找到了,返回下标索引
		{
			return p - _str;
		}
	}
	//substr
	my_string my_string::substr(size_t pos, size_t len)
	{
		size_t n = strlen(_str);
		assert(pos >= 0);
		assert(pos < n);//判断拷贝位置有效
		my_string tmp;//调用默认构造
		tmp._str = new char[len + 1];
		//进行拷贝
		for (size_t i = pos; i < pos + len; i++)
		{
			tmp._str[i - pos] = _str[i];
		}
		tmp._str[len] = '\0';
		tmp._size = tmp._capacity = len;//修改容量和长度
		return tmp;
	}
	//==
	//s1==s2
	bool my_string::operator==(const my_string& s)const
	{
		return strcmp(_str, s._str) == 0;//判断返回值是否等于0
	}
	//!=
	bool my_string::operator!=(const my_string& s)const
	{
		return !(*this == s);//代码复用
	}
	//<
	bool my_string::operator<(const my_string& s)const
	{
		return strcmp(_str, s._str) < 0;
	}
	//<=
	bool my_string::operator<=(const my_string& s)const
	{
		return (*this == s) || (*this < s);
	}
	//>
	bool my_string::operator>(const my_string& s)const
	{
		return !(*this <= s);
	}
	//>=
	bool my_string::operator>=(const my_string& s)const
	{
		return !(*this < s);
	}
	/*ostream& operator<<(ostream& out, my_string& s)
	{
		out << "_str:" << s._str << endl;
		out << "_size:" << s._size << endl;
		out << "_capacity:" << s._capacity << endl;
		return out;
	}*/
	ostream& operator<<(ostream& out, my_string& s)
	{
		cout << s._str;
		return out;
	}
	>>运算符重载
	//istream& operator>>(istream& in, my_string& s)
	//{
	//	char ch;
	//	in >> ch;//err in忽略空格和换行符
	//	while (ch != ' ' && ch != '\n')
	//	{
	//		s += ch;
	//		in >> ch;
	//	}
	//	return in;
	//}
	>>运算符重载
	//istream& operator>>(istream& in, my_string& s)
	//{
	//	//清理原来的字符串
	//	s.clear();
	//	char ch = in.get();//调用get
	//	while (ch != ' ' && ch != '\n')
	//	{
	//		s += ch;
	//		ch = in.get();
	//	}
	//	return in;
	//}
	//>>运算符重载(优化版)
	istream& operator>>(istream& in, my_string& s)
	{
		//清理原来的字符串
		s.clear();
		const size_t N = 1024;
		char arr[N];//使用一个临时数组(出了当前作用域就销毁)来存储写入的字符数据
		int i = 0;
		char ch = in.get();//调用get
		while (ch != ' ' && ch != '\n')
		{
			arr[i++] = ch;
			if (i == N - 1)
			{
				arr[i] = '\0';
				s += arr;//字符串很长的情况下,调用+=可以按需扩容
				i = 0;//i重新开始保存数据
			}
			ch = in.get();
		}
		if (i > 0)//arr里面还有字符数据
		{
			arr[i] = '\0';//末尾置为'\0'再进行插入
			s += arr;
		}
		return in;
	}
	//getline
	istream& getline(istream& in, my_string& s, char end)
	{
		//清理原来的字符串
		s.clear();
		const size_t N = 1024;
		char arr[N];//使用一个临时数组(出了当前作用域就销毁)来存储写入的字符数据
		int i = 0;
		char ch = in.get();//调用get
		while (ch != end)
		{
			arr[i++] = ch;
			if (i == N - 1)
			{
				arr[i] = '\0';
				s += arr;//字符串很长的情况下,调用+=可以按需扩容
				i = 0;//i重新开始保存数据
			}
			ch = in.get();
		}
		if (i > 0)//arr里面还有字符数据
		{
			arr[i] = '\0';//末尾置为'\0'再进行插入
			s += arr;
		}
		return in;
	}
}

test.cpp

代码语言:javascript
代码运行次数:0
运行
复制
#include"string.h"
namespace Xiaodu
{
	void test1()
	{
		my_string s1("Hello!!!");
		my_string s2;
		my_string s3(6, '6');
		cout << s1 << endl;
		cout << s2 << endl;
		cout << s3 << endl;
	}
	void test2()
	{
		my_string s1("Hello!");
		my_string s2(s1);//拷贝构造
		cout << s1 << endl;
		cout << s2 << endl;
		my_string s3("Xiaodu!");
		my_string s4("Haha!");
		s4 = s3 = s1;//连续赋值
		cout << s3 << endl;
		cout << s4 << endl;
	}
	void test3()
	{
		my_string s1("Hello!");
		s1.reserve(5);
		cout << s1 << endl;
		s1.reserve(10);
		cout << s1 << endl;
	}
	void test4()
	{
		my_string s1("HH");
		cout << s1 << endl;
		s1.push_back('X');
		s1.push_back('X');
		s1.push_back('X');
		s1.push_back('X');
		s1.push_back('X');
		s1.push_back('X');
		s1.push_back('X');
		cout << s1 << endl;
	}
	void test5()
	{
		my_string s1("Hello!"); 
		cout << s1 << endl;
		s1.append(" Xiaodu!");
		cout << s1 << endl;
		s1 += 'h';
		cout << s1 << endl;
		s1 += "HHH";
		cout << s1 << endl;

	}
	void test6()
	{
		my_string s1 = "XXXXXX";
		cout << s1 << endl;
		s1.insert(2, 8, 'H');
		cout << s1 << endl;
		s1.insert(4,"DDD");
		cout << s1 << endl;
		s1.erase(4, 6);
		cout << s1 << endl;
		s1.erase(6, 5);
		cout << s1 << endl;
	}
	void test7()
	{
		my_string s1("Hello!");
		if (s1.find('l', 2) != -1)//判断是不是等于npos
		{
			cout << "找到了,下标是" << s1.find('l', 2) << endl;
		}
		else
		{
			cout << "没有找到" << endl;;
		}
		if (s1.find('X') != -1)
		{
			cout << "找到了,下标是" << s1.find('X') << endl;
		}
		else
		{
			cout << "没有找到" << endl;;
		}
	}
	void test8()
	{
		my_string s1("Hello,World! Hello,Xiaodu!");
		size_t ret1 = s1.find("Hello");
		if (ret1 != -1)
		{
			cout << "找到了,下标是" << ret1 << endl;
		}
		else
		{
			cout << "没有找到" << endl;;
		}
		size_t ret2 = s1.find("Hello", 8);
		if (ret2 != -1)
		{
			cout << "找到了,下标是" << ret2 << endl;
		}
		else
		{
			cout << "没有找到" << endl;;
		}
		size_t ret3 = s1.find("XXX");
		if (ret3 != -1)
		{
			cout << "找到了,下标是" << ret3 << endl;
		}
		else
		{
			cout << "没有找到" << endl;;
		}
	}
	void test9()
	{
		my_string s1 = "Hello,Xiaodu!";
		my_string r1 = s1.substr(0, 5);
		cout << s1 << endl;
		cout << r1 << endl;
	}
	void test10()
	{
		string s1("Hello!");
		string s2("Hello!");
		string s3("Hello! Xiaodu");
		if (s1 == s2)
		{
			cout << "s1 == s2" << endl;
		}
		else
		{
			cout << "s1!=s2" << endl;
		}
		if (s1 == s3)
		{
			cout << "s1 == s3" << endl;
		}
		else
		{
			cout << "s1!=s3" << endl;
		}
		if (s1 <= s3)
		{
			cout << "s1 <= s3" << endl;
		}
		if (s3 >= s1)
		{
			cout << "s3 >= s1" << endl;
		}
	}
	void test11()
	{
		my_string s1("Hello!");
		my_string s2("Xiaodu!");
		cout << s1 << s2 << endl;
		cin >> s1 >> s2;
		cout << s1 << s2 << endl;
		my_string s3;
		cin >> s3;
		cout << s3 << endl;
	}
	void test12()
	{
		my_string s1("Haha!");
		my_string s2;
		my_string s3;
		cout << s1 << endl;
		cout << s2 << endl;
		getline(cin, s1);
		getline(cin, s2);
		cout << s1 << endl;
		cout << s2 << endl;
		getline(cin, s3, '!');//也可以自己指定一行结束符号
		cout << s3 << endl;
	}
}
int main()
{
	//Xiaodu::test1();
	Xiaodu::test2();
	//Xiaodu::test3();
	//Xiaodu::test4();
	//Xiaodu::test5();
	//Xiaodu::test6();
	//Xiaodu::test7();
	//Xiaodu::test8();
	//Xiaodu::test9();
	//Xiaodu::test10();
	//Xiaodu::test11();
	Xiaodu::test12();
	return 0;
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-03-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • string.h
  • string.cpp
  • test.cpp
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档