第四章:手撕string类(部分)

一、头文件

#define _CRT_SECURE_NO_WARNINGS 1
#include<assert.h>//断言库
#include<iostream>
#include<string>
using namespace std;

namespace wxt//写在自己的命名空间中
{
	class string
	{
	public:
		string(const char* str = "");//带参构造,给缺省处理空字符串的情况
		~string();//析构
		size_t size() const;//返回对象大小
		size_t capacity() const;//对象容量
		char& operator[](size_t pos);//对下标引用操作符的重载
		const char operator[](size_t pos) const;//下标引用操作符的const重载
		typedef char* iterator;//迭代器
		iterator begin();//开始迭代器
		iterator end();//结束迭代器
		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);//任意位置插入字符
		bool operator<(const string& s) const;//符号重载
		bool operator==(const string& s) const;
		bool operator<=(const string& s) const;
		bool operator>(const string& s) const;
		bool operator>=(const string& s) const;
		bool operator!=(const string& s) const;
		void clear();//情况对象数据
		const char* str() const;//以字符串返回对象
		typedef char* iterator;//针对const对象的迭代器
		iterator begin() const;
		iterator end() const;
//——————————————————————————————
//——————————————————————————————
		void insert(size_t pos, const char* str);//任意插入字符串
		void erase(size_t pos, size_t len = std::string::npos);//删除字符或字符串
		void rsize(size_t n, char ch = '\0');//设置对象大小
		size_t find(char ch, size_t pos = 0) const;//查找对象中指定字符
		size_t find(const char* str, size_t pos = 0) const;//查找对象中指定字符串
		string substr(size_t pos = 0, size_t len = std::string::npos) const;//截取对象部分元素并作为一个新的元素
	private:
		char* _str;
		size_t _size;
		size_t _capacity;
	};
	ostream& operator<<(ostream& out, const string& s);//流输出重载
	istream& operator>>(istream& in, string& s);//流提取重载
}

二、函数具体实现解析:

2.1构造函数:

  • 可以有参也可以无参
  • 声明给缺省值,定义不给缺省值。使用一个不包含任何数据的双引号作为缺省值,是因为双引号可以表示一个字符串,自动包含一个'\0'。就可以不用写无参构造。
  • 初始化列表完成对大小和容量的初始化,函数体内完成空间的开辟和内容的拷贝。
//声明
string(const char* str = "");//带参构造,给缺省处理空字符串的情况

//定义
wxt::string::string(const char* str)//给一个缺省值,处理传空字符串的情况
	:_size(strlen(str))//大小开辟为传来的字符串的长度
	, _capacity(_size)//容量设置为字符串的大小
{
	_str = new char[_capacity + 1];//多开辟一个字节空间,存放\0
	strcpy(_str, str);//将空字符串拷贝过去
}

2.2析构函数

  • 主要完成释放空间,指针置空,大小和容量归零。
//声明
~string();


//定义
wxt::string::~string()
{
	delete[] _str;//释放对象在堆上动态开辟的空间
	_str = nullptr;//将指向堆上空间的指针置空
	_size = _capacity = 0;//将大小和容量置空
}

2.3返回对象的大小和容量:

  • 加上const修饰this指针,使得值不可被修改。
//声明
size_t size() const;
size_t capacity() const;


//定义
size_t wxt::string::size() const//返回对象大小,加const修饰*this不被修改
{
	return _size;
}

size_t wxt::string::capacity() const//返回容量大小,加const成员修饰this指针
{
	return _capacity;
}

2.4下标引用操作符的重载:

  • 作用是可以像操作字符串一样操作string对象
  • 使用引用返回,就可以间接修改对象指定下标处的元素。
  • 加上断言,处理错误传递下标的情况
//声明
char& operator[](size_t pos);



//定义
char& wxt::string::operator[](size_t pos)//传引用返回,可以修改指定下标处字符
{
	assert(pos < _size);//断言下标为合法位置
	return _str[pos];//返回对象下标
}

2.5下标引用操作符的const版本重载:

  • const版本主要用于下标操作const修饰的string对象
  • 由于和非const版本的参数完全相同,需要加上const成员修饰this指针构成函数重载。
//声明
const char operator[](size_t pos) const;



//定义
const char wxt::string::operator[](size_t pos) const
//前面的const修饰函数,表示该函数为const修饰的string对象使用
//后面的const修饰this指针,与上一个[]的运算符重载构成函数重载
{
	assert(pos < _size);
	return _str[pos];
}

2.6迭代器:

  • 迭代器实际返回的是一个指针,所以将char*类型的指针,重命名为iterator
  • begin返回_str即可,代表首元素的地址
//声明
typedef char* iterator;
iterator begin();
iterator end();


//定义
wxt::string::iterator wxt::string::begin()
{
	return _str;//返回字符串名字,相当于首元素地址
}

wxt::string::iterator wxt::string::end()
{
	return _str + _size;//返回最后一个字符后一个的地址
						//相当于返回\0的地址,原string对象end-1才是最后一个字符地址
}

2.7针对const对象的迭代器:

  • 思路同上,加上const成员修饰this指针,使得构成函数重载
//声明
typedef char* iterator;
iterator begin() const;
iterator end() const;


//定义
wxt::string::iterator wxt::string::begin() const
{
	return _str;
}
wxt::string::iterator wxt::string::end() const
{
	return _str + _size;
}

2.8预留空间函数:

  • 如果要求预留的空间大于对象当前容量才进行扩容,否则不进行扩容。
  • 思路就是数据的迁移,先开要求大小的新空间,将旧空间的数据迁移过去,释放旧空间,对象中指向旧空间的指针指向新空间,更新对象的容量。
//声明
void reserve(size_t n);



//定义
void wxt::string::reserve(size_t n)
{
	if (n > _capacity)//判断,如果预扩容大小大于原容量才扩容
	{
		char* tmp = new char[n + 1];//开辟所需空间
		strcpy(tmp, _str);//拷贝原空间数据到开辟好的空间
		delete[] _str;//释放原空间
		_str = tmp;//原空间指针指向新空间
		_capacity = n;//更新对象容量
	}
}

2.9尾插:

  • 首先判断是否需要扩容,需要则先扩容再处理数据的插入
//声明
void push_back(char ch);



//定义
void wxt::string::push_back(char ch)
{
	if (_size == _capacity)//如果大小等于容量就扩容
	{
		reserve(_capacity == 0 ? 4 : _capacity * 2);//初始开4字节空间,之后双倍扩容,可以自己定义
	}
	_str[_size] = ch;//字符插入到对象末尾
	_size++;//对象大小加1
	_str[_size] = '\0';//对象末尾空间设置为'\0'
}

2.10尾插字符串

  • 思路:先判断是否需要扩容,处理好容量问题就可以将字符串拷贝到对象末尾。最后更新对象的大小即可
//声明
void append(const char* str);



//定义
void wxt::string::append(const char* str)
{
	size_t len = strlen(str);//求字符串长度
	if (len + _size > _capacity)//判断是否需要扩容
	{
		reserve(len + _size);
	}
	strcpy(_str + _size, str);//拷贝字符串到末尾
	_size = _size + len;//更新对象大小
}

2.11对+=的运算符重载:

  • 相当于尾插的符号版,直接复用尾插函数即可。
//声明
string& operator+=(char ch);
string& operator+=(const char* str);


//定义
wxt::string& wxt::string::operator+=(char ch)
{
	push_back(ch);
	return *this;
}

//引用返回,复用尾插
wxt::string& wxt::string::operator+=(const char* str)
{
	assert(str);
	append(str);
	return *this;
}

2.12插入单个字符:

  • 在指定位置插入单个字符。
  • 首先判断要插入位置是否合法。然后判断是否需要扩容。在指定位置开始向后挪动数据。将指定字符插入指定位置。更新对象大小。
//声明
void insert(size_t pos, char ch);



//定义
void wxt::string::insert(size_t pos, char ch)
{
	assert(pos <= _size);//判断插入位置是否合法
	if (_capacity == _size)//判断是否需要扩容
	{
		reserve(_capacity == 0 ? 4 : _capacity * 2);
	}
	size_t end = _size + 1;
	while (end > pos)//挪动数据,从pos位置向后挪动一位
								//同时会挪动'\0'!
	{
		_str[end] = _str[end - 1];
		end--;
	}
	_str[pos] = ch;//插入数据
	_size++;//更新对象大小
}

2.13插入字符串

  • 思路同插入单个字符。
//声明
void insert(size_t pos, const char* str);



//定义
void wxt::string::insert(size_t pos, const char* str)
{
	assert(pos <= _size);//断言下标是否合法
	size_t len = strlen(str);//求要插入的字符串的长度
	if (_size + len > _capacity)//超过空间则扩容
	{
		reserve(_size + len);
	}
	size_t end = _size + 1;//从后向前挪动,标记最后要操作的位置
	while (end > pos)//挪动数据
	{
		_str[end + len - 1] = _str[end - 1];
		--end;
	}
	_size += len;//更新对象大小
	strncpy(_str + pos, str, len);//使用strncpy不使用strcpy,防止将字符串的'\0'也拷贝过来
}

2.14运算符的重载:

  • 实现>和=,就可以复用实现其他符号了。
//声明:
bool operator<(const string& s) const;
bool operator==(const string& s) const;
bool operator<=(const string& s) const;
bool operator>(const string& s) const;
bool operator>=(const string& s) const;
bool operator!=(const string& s) const;


//定义
bool wxt::string::operator<(const wxt::string& s) const
{
	return strcmp(_str, s._str) < 0;
}

bool wxt::string::operator==(const string& s) const
{
	return strcmp(_str, s._str) == 0;
}

bool wxt::string::operator<=(const string& s) const
{
	return (*this < s) || (*this == s);
}

bool wxt::string::operator>(const string& s) const
{
	return !(*this < s);
}

bool wxt::string::operator>=(const string& s) const
{
	return (*this > s) || (*this == s);
}

bool wxt::string::operator!=(const string& s) const
{
	return !(*this == s);
}

2.15数据清理函数:

  • 完成空间数据的清理,只是清理数据,所以只会影响对象的大小,不会影响对象的容量。
//声明
void clear();



//定义
void wxt::string::clear()
{
	_size = 0;
	_str[0] = '\0';
}

2.16删除指定字符或字符串

//声明
void erase(size_t pos, size_t len = std::string::npos);



//定义
void wxt::string::erase(size_t pos, size_t len)
{
	assert(pos < _size);//判断下标是否合法,由于删除的是数据,所以合法的下标不能是_size
	if (len == std::string::npos || len + pos >= _capacity)
	{//处理全删和默认不传值的情况,不传值默认全删
		_str[pos] = '\0';//直接将指定位置设置为'\0'
		_size = pos;//更新对象大小,pos处为'\0',也就是_size的值
	}
	else
	{//处理删除部分数据的情况
		size_t begin = pos + len;//设置要挪动数据的起始位置
		while (begin <= _size)//循环挪动数据,结束条件为起始位置和末尾数据所在位置重叠
		{
			_str[begin - len] = _str[begin];
			++begin;
		}
		_size -= len;//更新对象大小
	}
}

2.17更改对象大小

  • 指定大小小于或等于对象大小,说明要截断数据
  • 大于,则说明要扩充,使用指定字符扩充即可
//声明
void rsize(size_t n, char ch = '\0');


//定义
void wxt::string::rsize(size_t n, char ch)
{
	if (n <= _size)//如果指定大小小于对象大小,说明需要删除超过指定大小意外的数据
	{
		_str[n] = '\0';
		_size = n;
	}
	else
	{
		reserve(n);//扩容,如果n小于_capacity,不扩容。
		while (_size < n)//如果n大于_size,说明需要插入指定字符
		{//循环,知道n等于_size再终止
			_str[_size] = ch;
			++_size;
		}
		_str[_size] = '\0';//将_size设置为\0
	}
}

2.18find系列

  • 查找字符,暴力匹配即可
  • 查找子串,使用strstr函数即可
//声明
size_t find(char ch, size_t pos = 0) const;
size_t find(const char* str, size_t pos = 0) const;


//定义
size_t wxt::string::find(char ch, size_t pos) const
{
	//不需要使用assert断言下标是否合法
	//因为,下标不合法和没有查到,都可以返回npos
	for (size_t i = pos; i < _size; i++)
	{
		if (_str[i] == ch)
		{
			return i;
		}
	}
	return std::string::npos;
}

//find查找字符串
size_t wxt::string::find(const char* str, size_t pos) const
{
	//无需assert断言,下标不合法返回npos即可
	const char* p = strstr(_str + pos, str);
	if (p)
	{
		return p - _str;//指针减去指针,得到相差的元素个数
	}
	return std::string::npos;
}

2.19截取对象的一部分作为新的对象

//声明
string substr(size_t pos = 0, size_t len = std::string::npos) const;


//定义
wxt::string wxt::string::substr(size_t pos, size_t len) const
{
	wxt::string s;//创建一个用于返回的对象
	size_t end = pos + len;//设置结束位置
	if (len == std::string::npos || len + pos >= _size)
	{
		len = _size - pos;//求出要截取的长度,用于之后开辟空间
		end = _size;//如果是全取,更新结束位置为最后一个元素的后一个位置,也就是'\0'处
	}
	s.reserve(len);//一次开辟好空间
	for (size_t i = pos; i < end; i++)
	{
		s += _str[i];//将截取的子串,一个字符一个字符的添加到要返回的对象中
	}
	return s;//返回子串对象
}

2.20流提取的重载:

  • in.get可以获取任意字符,包括空格和换行符
//声明
istream& operator>>(istream& in, string& s);


//定义
istream& wxt::operator>>(istream& in, string& s)
{
	s.clear();//清空对象
	char ch;
	ch = in.get();//使用get方法获取一个流字符
	while (ch != ' ' && ch != '\n')//当获取的字符不为空格和换行时
	{
		s += ch;//字符尾插到对象
		ch = in.get();//获取下一个字符
	}
	return in;//返回istream指针
}

2.21流输出的重载:

//声明
ostream& operator<<(ostream& out, const string& s);


//定义
ostream& wxt::operator<<(ostream& out, const wxt::string& s)
{
	for (size_t i = 0; i < s.size(); i++)//循环打印
	{
		out << s[i];
	}
	return out;//返回istream指针
}

三、函数文件

#pragma once
#include "string.h"

//无参构造,可以被下面的带参构造+缺省的方式替代
//wxt::string::string()
//	:_str(new char[1]{'\0'})//空string对象也要包含一个字符\0占位
//	,_size(0)//大小和容量都初始化为0,容量大小不包含\0在内
//	,_capacity(0)
//{}

//带参构造
wxt::string::string(const char* str)//给一个缺省值,处理传空字符串的情况
	:_size(strlen(str))//大小开辟为传来的字符串的长度
	, _capacity(_size)//容量设置为字符串的大小
{
	_str = new char[_capacity + 1];//多开辟一个字节空间,存放\0
	strcpy(_str, str);//将空字符串拷贝过去
}

//析构
wxt::string::~string()
{
	delete[] _str;//释放对象在堆上动态开辟的空间
	_str = nullptr;//将指向堆上空间的指针置空
	_size = _capacity = 0;//将大小和容量置空
}

size_t wxt::string::size() const//返回对象大小,加const修饰*this不被修改
{
	return _size;
}

size_t wxt::string::capacity() const//返回容量大小,加const成员修饰this指针
{
	return _capacity;
}

char& wxt::string::operator[](size_t pos)//传引用返回,可以修改指定下标处字符
{
	assert(pos < _size);//断言下标为合法位置
	return _str[pos];//返回对象下标
}

const char wxt::string::operator[](size_t pos) const
//前面的const修饰函数,表示该函数为const修饰的string对象使用
//后面的const修饰this指针,与上一个[]的运算符重载构成函数重载
{
	assert(pos < _size);
	return _str[pos];
}

wxt::string::iterator wxt::string::begin()
{
	return _str;//返回字符串名字,相当于首元素地址
}

wxt::string::iterator wxt::string::end()
{
	return _str + _size;//返回最后一个字符后一个的地址
								//相当于返回\0的地址,原string对象end-1才是最后一个字符地址
}


//扩容函数,思路是先判断是否需要扩容,
//需要扩容,先开辟空间,然后将原空间内容拷贝过去
//释放原空间,更新指针指向新空间,更新对象容量大小
void wxt::string::reserve(size_t n)
{
	if (n > _capacity)//判断,如果预扩容大小大于原容量才扩容
	{
		char* tmp = new char[n + 1];//开辟所需空间
		strcpy(tmp, _str);//拷贝原空间数据到开辟好的空间
		delete[] _str;//释放原空间
		_str = tmp;//原空间指针指向新空间
		_capacity = n;//更新对象容量
	}
}

//尾插,思路:
//首先判断空间是否足够,不足扩容
//足够,将字符放在末尾,将最后一位的后一位设为\0
void wxt::string::push_back(char ch)
{
	if (_size == _capacity)
	{
		reserve(_capacity == 0 ? 4 : _capacity * 2);
	}
	_str[_size] = ch;
	_size++;
	_str[_size] = '\0';
}

//尾插字符串,思路:
//判断是否需要扩容,将字符串拷贝到对象末尾,更新对象大小
void wxt::string::append(const char* str)
{
	size_t len = strlen(str);//求字符串长度
	if (len + _size > _capacity)//判断是否需要扩容
	{
		reserve(len + _size);
	}
	strcpy(_str + _size, str);//拷贝字符串到末尾
	_size = _size + len;//更新对象大小
}

//运算符重载+=,引用返回,复用尾插,返回对象this指针
wxt::string& wxt::string::operator+=(char ch)
{
	push_back(ch);
	return *this;
}

//引用返回,复用尾插
wxt::string& wxt::string::operator+=(const char* str)
{
	assert(str);
	append(str);
	return *this;
}

//插入,思路:
//先判断是否扩容,挪动数据,插入数据
void wxt::string::insert(size_t pos, char ch)
{
	assert(pos <= _size);//判断插入位置是否合法
	if (_capacity == _size)//判断是否需要扩容
	{
		reserve(_capacity == 0 ? 4 : _capacity * 2);
	}
	size_t end = _size + 1;
	while (end > pos)//挪动数据,从pos位置向后挪动一位
								//同时会挪动'\0'!
	{
		_str[end] = _str[end - 1];
		end--;
	}
	_str[pos] = ch;//插入数据
	_size++;//更新对象大小
}

//void wxt::string::insert(size_t pos, const char* str)
//{
//	assert(pos <= _size);
//	assert(str);
//	size_t len = strlen(str);
//	if (_size + len > _capacity)
//	{
//		reserve(_size + len);
//	}
//	_size += len;
//	size_t end = _capacity;
//	while (end > pos + len)
//	{
//		_str[end - 1] = _str[end - len - 1];
//		--end;
//	}
//	strcpy(_str + pos, str);
//}


//void wxt::string::erase(size_t pos, size_t len = npos)
//{
//	assert(pos <= _size);
//	if (len < _capacity - _size)
//	{
//		while (len > 0)
//		{
//
//		}
//	}
//}

//直接比较对象中的字符串,根据返回值判断比较结果
bool wxt::string::operator<(const wxt::string& s) const
{
	return strcmp(_str, s._str) < 0;
}

bool wxt::string::operator==(const string& s) const
{
	return strcmp(_str, s._str) == 0;
}

bool wxt::string::operator<=(const string& s) const
{
	return (*this < s) || (*this == s);
}

bool wxt::string::operator>(const string& s) const
{
	return !(*this < s);
}

bool wxt::string::operator>=(const string& s) const
{
	return (*this > s) || (*this == s);
}

bool wxt::string::operator!=(const string& s) const
{
	return !(*this == s);
}

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

const char* wxt::string::str() const
{
	return _str;
}

ostream& wxt::operator<<(ostream& out, const wxt::string& s)
{
	for (size_t i = 0; i < s.size(); i++)//循环打印
	{
		out << s[i];
	}
	return out;//返回istream指针
}

istream& wxt::operator>>(istream& in, string& s)
{
	s.clear();//清空对象
	char ch;
	ch = in.get();//使用get方法获取一个流字符
	while (ch != ' ' && ch != '\n')//当获取的字符不为空格和换行时
	{
		s += ch;//字符尾插到对象
		ch = in.get();//获取下一个字符
	}
	return in;//返回istream指针
}

//针对const对象的迭代器。
wxt::string::iterator wxt::string::begin() const
{
	return _str;
}
wxt::string::iterator wxt::string::end() const
{
	return _str + _size;
}

//————————————————————————————————————————————————————————————————
//————————————————————————————————————————————————————————————————

//插入字符串
void wxt::string::insert(size_t pos, const char* str)
{
	assert(pos <= _size);//断言下标是否合法
	size_t len = strlen(str);//求要插入的字符串的长度
	if (_size + len > _capacity)//超过空间则扩容
	{
		reserve(_size + len);
	}
	size_t end = _size + 1;//从后向前挪动,标记最后要操作的位置
	while (end > pos)//挪动数据
	{
		_str[end + len - 1] = _str[end - 1];
		--end;
	}
	_size += len;//更新对象大小
	strncpy(_str + pos, str, len);//使用strncpy不使用strcpy,防止将字符串的'\0'也拷贝过来
}

//void wxt::string::insert(size_t pos, const char* str)
//{
//	assert(pos <= _size);//断言下标是否合法
//	size_t len = strlen(str);//求要插入的字符串的长度
//	if (_size + len > _capacity)//超过空间则扩容
//	{
//		reserve(_size + len);
//	}
//	size_t end = _size + len + 1;//从后向前挪动,标记最后要操作的位置
//	while (end > _size)//挪动数据
//	{
//		_str[end - 1] = _str[end - 1 - len];
//		--end;
//	}
//	_size += len;//更新对象大小
//	strncpy(_str + pos, str, len);//使用strncpy不使用strcpy,防止将字符串的'\0'也拷贝过来
//}


//删除字符或字符串
void wxt::string::erase(size_t pos, size_t len)
{
	assert(pos < _size);//判断下标是否合法,由于删除的是数据,所以合法的下标不能是_size
	if (len == std::string::npos || len + pos >= _capacity)
	{//处理全删和默认不传值的情况,不传值默认全删
		_str[pos] = '\0';//直接将指定位置设置为'\0'
		_size = pos;//更新对象大小,pos处为'\0',也就是_size的值
	}
	else
	{//处理删除部分数据的情况
		size_t begin = pos + len;//设置要挪动数据的起始位置
		while (begin <= _size)//循环挪动数据,结束条件为起始位置和末尾数据所在位置重叠
		{
			_str[begin - len] = _str[begin];
			++begin;
		}
		_size -= len;//更新对象大小
	}
}

//分两种情况,n小于_size和n大于_size
//小于则直接设置‘\0’,大于先扩容,然后填充字符
void wxt::string::rsize(size_t n, char ch)
{
	if (n <= _size)
	{
		_str[n] = '\0';
		_size = n;
	}
	else
	{
		reserve(n);//扩容,如果n小于_capacity,不扩容。
		while (_size < n)//如果n大于_size,说明需要插入指定字符
		{//循环,知道n等于_size再终止
			_str[_size] = ch;
			++_size;
		}
		_str[_size] = '\0';//将_size设置为\0
	}
}

//find查找字符
//size_t wxt::string::find(char ch, size_t pos) const
//{
//	//不需要使用assert断言下标是否合法
//	//因为,下标不合法和没有查到,都可以返回npos
//	while (pos < _size)
//	{
//		if (_str[pos] == ch)
//		{
//			return pos;
//		}
//		++pos;
//	}
//	return std::string::npos;
//}

size_t wxt::string::find(char ch, size_t pos) const
{
	//不需要使用assert断言下标是否合法
	//因为,下标不合法和没有查到,都可以返回npos
	for (size_t i = pos; i < _size; i++)
	{
		if (_str[i] == ch)
		{
			return i;
		}
	}
	return std::string::npos;
}

//find查找字符串
size_t wxt::string::find(const char* str, size_t pos) const
{
	//无需assert断言,下标不合法返回npos即可
	const char* p = strstr(_str + pos, str);
	if (p)
	{
		return p - _str;//指针减去指针,得到相差的元素个数
	}
	return std::string::npos;
}

wxt::string wxt::string::substr(size_t pos, size_t len) const
{
	wxt::string s;//创建一个用于返回的对象
	size_t end = pos + len;//设置结束位置
	if (len == std::string::npos || len + pos >= _size)
	{
		len = _size - pos;//求出要截取的长度,用于之后开辟空间
		end = _size;//如果是全取,更新结束位置为最后一个元素的后一个位置,也就是'\0'处
	}
	s.reserve(len);//一次开辟好空间
	for (size_t i = pos; i < end; i++)
	{
		s += _str[i];//将截取的子串,一个字符一个字符的添加到要返回的对象中
	}
	return s;//返回子串对象
}

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

S+叮当猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值