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

C++中string类的模拟实现

目录

1.string类的结构

2.默认成员函数

2.1.默认构造函数

2.2拷贝构造函数 

2.3赋值运算符重载 

2.4析构函数

 3.迭代器(Iterators)

4.string类的空间操作(Capacity)

4.1size()

4.2capacity()

4.3clear() 

4.4reserve()

5.元素访问(Element access)

6.string类的修改操作(Modifiers) 

6.1push_back()

6.2append() 

6.3operator+=()

6.4swap()

6.5insert() 

6.6 erase()

7.字符串操作(String operations) 

7.1c_str()

7.2find()

7.3substr()

8.非成员函数重载(Non-member function overloads) 

8.1关系运算符(relational operators)

8.2输入输出重载(operator>> and operator<<) 

 8.2.1输出运算符重载

8.2.2输入运算符重载

9.参考代码

9.1string.h 

9.2string.cpp

9.3Test.cpp 


1.string类的结构

		char* _str = nullptr;
		size_t _capacity = 0;
		size_t _size = 0;
		//这里可以直接给默认值,相当于定义,因为有const,只有整型可以
		//static const size_t npos = -1;
		static const size_t npos;

        string类结构里有一个_str指针,指向存储字符的数组,_capacity表示当前string的空间大小,_size表示当前string中的有效元素个数,静态常量npos默认等于-1,表示整形的最大值。 

2.默认成员函数

2.1.默认构造函数

		//默认构造函数
		string()
			//直接给空指针在使用.c_str()时进行打印对空指针进行了解引用
			:_str(new char[1] {'\0'})
			//:_str(nullptr)
			,_size(0)
			,_capacity(0)
		{}
		
		//带参的构造
		string(const char* str)
		{
			_size = strlen(str);
			//_capacity不包含\0
			_capacity = _size;
			//开空间的时候多开一个用于存储\0
			_str = new char[_capacity + 1];
			strcpy(_str, str);
		}

        这里的默认构造函数不能给_str空指针,如果是个空串进行打印的话,会对空指针进行解引用会导致程序崩溃。 因为要存一个'\0',所以空串也要开一个空间。

        这里可以把上述两个构造合成一个构造函数。

//将上述两个构造函数合并成一个全缺省的构造函数
string(const char* str = "")	//空的常量字符串默认包含一个\0
{
	_size = strlen(str);
	_capacity = _size;
	_str = new char[_capacity + 1];
	strcpy(_str, str);	//strcpy先拷贝再判断,会拷贝\0
}

2.2拷贝构造函数 

        1.传统写法

//传统写法
string(const string& s)
{
	_str = new char[s._capacity + 1];    //多开一个空间给'\0'
	strcpy(_str, s._str);                //拷贝数据
	_size = s._size;
	_capacity = s._capacity;
}

        2.现代写法

void swap(string& s) 
{
	std::swap(_str, s._str);
	std::swap(_size, s._size);
	std::swap(_capacity, s._capacity);
}

//现代写法
string(const string& s)
{
	string tmp(s._str);
	swap(tmp);
}

        这里调用库里面的交换函数,交换string结构里面的数据。然后在拷贝函数中用被拷贝的string对象s中的_str构造一个临时对象,然后进行交换,函数结束之后这个临时对象自动销毁,构造出一个与s一样的新对象。

2.3赋值运算符重载 

         1.写法1

		string& operator=(const string& s)
		{
			if (this != &s)    //检测是否是自己给自己赋值
			{
				delete[] _str;    //释放原来对象的空间
				_str = new char[s._capacity + 1];    //new一个和s一样大的空间
				strcpy(_str, s._str);    //拷贝数据
				_size = s._size;
				_capacity = s._capacity;
			}
			return *this;
		}

        2.写法2 

		string& operator=(const string& s)
		{
			if (this != &s)
			{
				string tmp(s);
				swap(tmp);
			}

			return *this;
		}

        这个和拷贝函数的现代写法思路一样。

        3.写法3

		string& operator=(string tmp)
		{
			swap(tmp);	//这里虽然tmp被交换了,但是形参的改变不影响实参
			return *this;
		}

        这里直接使用传值传参,然后进行交换,函数结束之后并不会影响实参。 

2.4析构函数

		~string()
		{
			if (_str)
			{
				delete[] _str;
				_str = nullptr;   
				_size = 0;
				_capacity = 0;
			}
		}

 3.迭代器(Iterators)

		// iterator
		typedef char* iterator;
		typedef const char* const_iterator;
		iterator begin()
		{
			return _str;
		}
		iterator end()
		{
			return _str + _size;
		}

		const_iterator begin() const    //函数重载,重载迭代器用于const对象
		{
			return _str;
		}

		const_iterator end() const
		{
			return _str + _size;
		}

         因为string的底层是利用数组进行存储的,所以这里直接利用原始指针作为迭代器即可,用两个typedef关键字将char*类型和const char*类型改为迭代器的名字。

4.string类的空间操作(Capacity)

4.1size()

		size_t size() const
		{
			return _size;
		}

4.2capacity()

		size_t capacity() const
		{
			return _capacity;
		}

4.3clear() 

         清除string对象里面的数据,但是这里不缩容_capacity不改变。

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

4.4reserve()

         该函数在string.cpp里面实现的,所以加上了类域限定符.

	void string::reserve(size_t n)
	{
		if (n > _capacity)
		{
			char* tmp = new char[n + 1];
			strcpy(tmp, _str);
			delete[] _str;
			_str = tmp;
			_capacity = n;
		}
	}

5.元素访问(Element access)

        这里仅实现[]的重载。 

		char& operator[](size_t index)
		{
			assert(index < _size);

			return _str[index];
		}
		const char& operator[](size_t index)const
		{
			assert(index < _size);

			return _str[index];
		}

6.string类的修改操作(Modifiers

6.1push_back()

        尾插一个字符.

	void string::push_back(char c)
	{
		//扩容
		if (_size == _capacity)
		{
			reserve(_capacity == 0 ? 4 : _capacity * 2);
		}

		_str[_size] = c;
		++_size;
		_str[_size] = '\0';
	}

6.2append() 

        尾插一个字符串.这里扩容保持一个对齐的原则,如果需要的空间大于原来空间的两倍,则需要多少开多少,如果小于原来的两倍,则开2倍.

	void string::append(const char* str)
	{
		size_t len = strlen(str);    //计算尾插的str大小
		if (_size + len > _capacity)
		{
			//需要的空间大于原空寂的2倍,需要多少开多少,小于2倍开2倍
			reserve((_size + len) > (2 * _capacity) ? (_size + len) : (2 * _capacity));
		}

		strcpy(_str + _size, str);
		_size += len;
	}

6.3operator+=()

        +=运算符的重载实现能加一个字符,也能加一个字符串,复用上述两个接口进行实现.

	string& string::operator+=(char c)
	{
		push_back(c);
		return *this;
	}
	string& string::operator+=(const char* str)
	{
		append(str);
		return *this;
	}

6.4swap()

		void swap(string& s) 
		{
			std::swap(_str, s._str);
			std::swap(_size, s._size);
			std::swap(_capacity, s._capacity);
		}

6.5insert() 

	// 在pos位置上插入字符c/字符串str
	void string::insert(size_t pos, char c)
	{
		assert(pos <= _size);

		if (_size == _capacity)
		{
			reserve(_capacity == 0 ? 4 : _capacity * 2);
		}
		//这里用size_t类型头插会出错,因为end永远都小于不了0
		//size_t end = _size;	//从最后一个\0开始往后挪动数据
		//用int end在与pos比较时会提升为size_t类型,也会出错
		//int end = _size;
		//while (end >= (int)pos)
		//{
		//	_str[end + 1] = _str[end];
		//	end--;
		//}

		//挪动数据,_size处是\0,从后面的\0开始挪动
		size_t end = _size + 1;
		while (end > pos)    
		{
			_str[end] = _str[end - 1];
			end--;
		}

		_str[pos] = c;
		++_size;
	}
	//在pos位置插入字符串
    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 - len];
			--end;
		}
        //插入字符串
		for (size_t i = 0; i < len; i++)
		{
			_str[pos + i] = str[i];
		}

		_size += len;
	}

6.6 erase()

        如果需要删除的len的长度大于从pos到最后位置的长度,则修正len之后进行删除.

	// 删除pos位置上之后的len个元素
	void string::erase(size_t pos, size_t len)
	{
		assert(pos < _size);
        
        //如果删除的元素个数大于从pos到最后的个数,修正一下len
		if (len >= _size - pos)
		{
			_str[pos] = '\0';
			_size = pos;
		}
		else
		{
			for (size_t i = pos + len; i <= _size; i++)
			{
				_str[i - len] = _str[i];
			}
			_size -= len;
		}
	}

7.字符串操作(String operations) 

7.1c_str()

        这里返回string对象中的数组指针,可以说是返回C语言类型的字符串对象.

		//返回string中的指向字符串的指针
		const char* c_str() const
		{
			return _str;
		}

7.2find()

	// 返回c在string中第一次出现的位置
	size_t string::find(char c, size_t pos) const
	{
		assert(pos < _size);

		for (size_t i = pos; i < _size; i++)
		{
			if (_str[i] == c)
			{
				return i;
			}
		}
        
        //没找到返回最大的整数
		return npos;
	}

	// 返回子串s在string中第一次出现的位置
	size_t string::find(const char* s, size_t pos) const
	{
		assert(pos < _size);

        //调用库里面的strstr函数在自身中寻找子串
		const char* ptr = strstr(_str + pos, s);
		if (ptr == nullptr)
		{
			return npos;
		}
		else
		{
			return ptr - _str;
		}
	}

7.3substr()

	//返回子串
	string string::substr(size_t pos, size_t len) const
	{
		assert(pos < _size);
        
		//len大于剩余字符的长度,更新一下len
		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;
	}

8.非成员函数重载(Non-member function overloads) 

8.1关系运算符(relational operators)

        字符串的关系运算符与C语言中的compare()类似,这里直接复用库里面的compare()函数.

需要注意的是compare()函数是使用C语言中的字符串格式进行比较的,这里比较的是string对象中_str指向的数组.

//relational operators
	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 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 !(s1 == s2);
	}

8.2输入输出重载(operator>> and operator<<) 

         这里的输入和输出为什么重载成全局函数请参考C++类和对象(5)--日期类的实现中友元声明中的注释.

 8.2.1输出运算符重载

        遍历string对象一个一个输出即可.

	ostream& operator<<(ostream& _cout, const string& s)
	{
		for (auto ch : s)
		{
			_cout << ch;
		}

		return _cout;
	}

8.2.2输入运算符重载

        这里首先先清除s中原有的数据,然后在栈里面开一个256大小的buff(为了减少扩容的次数).这里用get()函数一个一个读取输入的字符,如果用输入运算符的话会忽略输入的空格和换行符.当一个buff满了之后拷贝到s中,跳出循环后如果buff中还有遗留的数据,则全部拷贝到s中.

	istream& operator>>(istream& _cin, string& s)
	{
		s.clear();

		const int N = 256;
		char buff[N];
		int i = 0;

		char ch;
		//in >> ch; 默认会忽略空格和换行符
		ch = _cin.get();
		while (ch != ' ' && ch != '\n')
		{
			buff[i++] = ch;
			if (i == N - 1)
			{
				buff[i] = '\0';
				s += buff;

				i = 0;
			}
			//in >> ch;
			ch = _cin.get();
		}

		if (i > 0)
		{
			buff[i] = '\0';
			s += buff;
		}

		return _cin;
	}

9.参考代码

        string实现在XiaoC这个命名空间中,上述的代码没有做测试,下面给出测试代码,有兴趣可以自行对接口进行测试.

9.1string.h 

#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <assert.h>
#include <string>
using namespace std;

namespace XiaoC
{
	class string
	{
		//friend ostream& operator<<(ostream& _cout, const XiaoC::string& s);
		//friend istream& operator>>(istream& _cin, XiaoC::string& s);
	public:
		默认构造函数
		//string()
		//	//直接给空指针在使用.c_str()时进行打印对空指针进行了解引用
		//	:_str(new char[1] {'\0'})
		//	//:_str(nullptr)
		//	,_size(0)
		//	,_capacity(0)
		//{}
		//
		带参的构造
		//string(const char* str)
		//{
		//	_size = strlen(str);
		//	//_capacity不包含\0
		//	_capacity = _size;
		//	//开空间的时候多开一个用于存储\0
		//	_str = new char[_capacity + 1];
		//	strcpy(_str, str);
		//}

		//将上述两个构造函数合并成一个全缺省的构造函数
		string(const char* str = "")	//空的常量字符串默认包含一个\0
		{
			_size = strlen(str);
			_capacity = _size;
			_str = new char[_capacity + 1];
			strcpy(_str, str);	//strcpy先拷贝再判断,会拷贝\0
		}


		//拷贝构造
		//传统写法
		//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);
		}

		//赋值重载
		//写法1
		//string& operator=(const 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;
		//}

		//写法2
		//string& operator=(const string& s)
		//{
		//	if (this != &s)
		//	{
		//		string tmp(s);
		//		swap(tmp);
		//	}
		//	return *this;
		//}

		//写法3
		string& operator=(string tmp)
		{
			swap(tmp);	//这里虽然tmp被交换了,但是形参的改变不影响实参
			return *this;
		}

		~string()
		{
			if (_str)
			{
				delete[] _str;
				_str = nullptr;
				_size = 0;
				_capacity = 0;
			}
		}

		// iterator
		typedef char* iterator;
		typedef const char* const_iterator;
		iterator begin()
		{
			return _str;
		}
		iterator end()
		{
			return _str + _size;
		}

		const_iterator begin() const
		{
			return _str;
		}

		const_iterator end() const
		{
			return _str + _size;
		}

		// modify
		void push_back(char c);
		void append(const char* str);
		string& operator+=(char c);
		string& operator+=(const char* str);

		void swap(string& s) 
		{
			std::swap(_str, s._str);
			std::swap(_size, s._size);
			std::swap(_capacity, s._capacity);
		}

		//返回string中的指向字符串的指针
		const char* c_str() const
		{
			return _str;
		}

		// capacity
		size_t size() const
		{
			return _size;
		}

		size_t capacity() const
		{
			return _capacity;
		}

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

		void reserve(size_t n);

		// access
		char& operator[](size_t index)
		{
			assert(index < _size);

			return _str[index];
		}
		const char& operator[](size_t index)const
		{
			assert(index < _size);

			return _str[index];
		}

		// 返回c在string中第一次出现的位置
		size_t find(char c, size_t pos = 0) const;

		// 返回子串s在string中第一次出现的位置
		size_t find(const char* s, size_t pos = 0) const;

		// 在pos位置上插入字符c/字符串str
		void insert(size_t pos, char c);
		void insert(size_t pos, const char* str);

		// 删除pos位置上的元素,并返回该元素的下一个位置
		void erase(size_t pos, size_t len = npos);

		//返回子串
		string substr(size_t pos = 0, size_t len = npos) const;

	private:
		char* _str = nullptr;
		size_t _capacity = 0;
		size_t _size = 0;
		//这里可以直接给默认值,相当于定义,因为有const,只有整型可以
		//static const size_t npos = -1;
		static const size_t npos;
	};

	//relational operators
	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& _cout, const string& s);
	istream& operator>>(istream& _cin, string& s);

}

9.2string.cpp

#include "string.h"
namespace XiaoC
{
	const size_t string::npos = -1;

	void string::push_back(char c)
	{
		//扩容
		if (_size == _capacity)
		{
			reserve(_capacity == 0 ? 4 : _capacity * 2);
		}

		_str[_size] = c;
		++_size;
		_str[_size] = '\0';
	}

	void string::append(const char* str)
	{
		size_t len = strlen(str);
		if (_size + len > _capacity)
		{
			//大于2倍,需要多少开多少,小于2倍开2倍
			reserve((_size + len) > (2 * _capacity) ? (_size + len) : (2 * _capacity));
		}

		strcpy(_str + _size, str);
		_size += len;
	}

	string& string::operator+=(char c)
	{
		push_back(c);
		return *this;
	}
	string& string::operator+=(const char* str)
	{
		append(str);
		return *this;
	}

	void string::reserve(size_t n)
	{
		if (n > _capacity)
		{
			char* tmp = new char[n + 1];
			strcpy(tmp, _str);
			delete[] _str;
			_str = tmp;
			_capacity = n;
		}
	}

	// 在pos位置上插入字符c/字符串str
	void string::insert(size_t pos, char c)
	{
		assert(pos <= _size);

		if (_size == _capacity)
		{
			reserve(_capacity == 0 ? 4 : _capacity * 2);
		}
		//这里用size_t类型头插会出错,因为end永远都小于不了0
		//size_t end = _size;	//从最后一个\0开始往后挪动数据
		//用int end在与pos比较时会提升为size_t类型,也会出错
		//int end = _size;
		//while (end >= (int)pos)
		//{
		//	_str[end + 1] = _str[end];
		//	end--;
		//}

		//挪动数据,_size处是\0,从后面的\0开始挪动
		size_t end = _size + 1;
		while (end > pos)
		{
			_str[end] = _str[end - 1];
			end--;
		}

		_str[pos] = c;
		++_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 - len];
			--end;
		}

		for (size_t i = 0; i < len; i++)
		{
			_str[pos + i] = str[i];
		}

		_size += len;
	}

	// 删除pos位置上之后的len个元素
	void string::erase(size_t pos, size_t len)
	{
		assert(pos < _size);

		if (len >= _size - pos)
		{
			_str[pos] = '\0';
			_size = pos;
		}
		else
		{
			for (size_t i = pos + len; i <= _size; i++)
			{
				_str[i - len] = _str[i];
			}
			_size -= len;
		}
	}

	// 返回c在string中第一次出现的位置
	size_t string::find(char c, size_t pos) const
	{
		assert(pos < _size);

		for (size_t i = pos; i < _size; i++)
		{
			if (_str[i] == c)
			{
				return i;
			}
		}

		return npos;
	}

	// 返回子串s在string中第一次出现的位置
	size_t string::find(const char* s, size_t pos) const
	{
		assert(pos < _size);

		const char* ptr = strstr(_str + pos, s);
		if (ptr == nullptr)
		{
			return npos;
		}
		else
		{
			return ptr - _str;
		}
	}

	//返回子串
	string string::substr(size_t pos, size_t len) const
	{
		assert(pos < _size);

		//len大于剩余字符的长度,更新一下len
		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;
	}

	//relational operators
	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 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 !(s1 == s2);
	}

	ostream& operator<<(ostream& _cout, const string& s)
	{
		for (auto ch : s)
		{
			_cout << ch;
		}

		return _cout;
	}
	istream& operator>>(istream& _cin, string& s)
	{
		s.clear();

		const int N = 256;
		char buff[N];
		int i = 0;

		char ch;
		//in >> ch; 默认会忽略空格和换行符
		ch = _cin.get();
		while (ch != ' ' && ch != '\n')
		{
			buff[i++] = ch;
			if (i == N - 1)
			{
				buff[i] = '\0';
				s += buff;

				i = 0;
			}
			//in >> ch;
			ch = _cin.get();
		}

		if (i > 0)
		{
			buff[i] = '\0';
			s += buff;
		}

		return _cin;
	}
}

9.3Test.cpp

#include "string.h"

namespace XiaoC
{
	//测试构造函数
	void test_string1()
	{
		string s1;
		string s2("hello world");

		cout << s1.c_str() << endl;
		cout << s2.c_str() << endl;
	}

	//测试遍历访问
	void test_string2()
	{
		string s1("hello world");
		cout << s1.c_str() << endl;

		//[] + 下标访问
		for (size_t i = 0; i < s1.size(); i++)
		{
			s1[i] += 2;
		}

		cout << s1.c_str() << endl;

		//范围for底层就是替代为迭代器
		for (auto e : s1)
		{
			cout << e << " ";
		}
		cout << endl;

		//通过迭代器遍历访问
		string::iterator it = s1.begin();
		while (it != s1.end())
		{
			cout << *it << " ";
			++it;
		}
		cout << endl;
	}

	//测试增删改查
	void test_string3()
	{
		string s1 = "hello world";
		s1 += 'x';
		s1 += 'c';

		cout << s1.c_str() << endl;

		s1 += " hello XiaoC";
		cout << s1.c_str() << endl;

		string s2 = "abcd";
		cout << s2.c_str() << endl;
		s2.insert(0, 'c');
		cout << s2.c_str() << endl;

		string s3 = "hello world";
		cout << s3.c_str() << endl;
		s3.insert(0, "xxx");
		cout << s3.c_str() << endl;

		string s4 = "hello world";
		cout << s4.c_str() << endl;
		s4.erase(0, 3);
		cout << s4.c_str() << endl;

		string s("test.cpp.zip");
		size_t pos = s.find('.');
		string suffix = s.substr(pos);
		cout << suffix.c_str() << endl;

		//拷贝构造
		string copy(s);
		cout << copy.c_str() << endl;

		//赋值运算符
		string s5 = "XiaoC";
		s5 = s;
		cout << s5.c_str() << endl;
	}

	//测试比较大小
	void test_string4()
	{
		string s1 = "helloworld";
		string s2 = s1;
		cout << (s1 == s2) << endl;
		cout << (s1 < s2) << endl;
	}

	//测试输入输出
	void test_string5()
	{
		string s1 = "hello world";
		cout << s1 << endl;

		string s2;
		cin >> s2;
		cout << s2 << endl;
	}

	//测试返回字串
	void test_string6()
	{
		string s1 = "hello world";
		string s2;
		s2 = s1.substr(6, 5);
		cout << s2 << endl;
	}
}
int main()
{
	//XiaoC::test_string1();
	//XiaoC::test_string2();
	//XiaoC::test_string3();
	//XiaoC::test_string4();
	XiaoC::test_string5();
	//XiaoC::test_string6();

	return 0;
}

 

 

 


http://www.kler.cn/news/310931.html

相关文章:

  • JDBC 编程
  • RockPlus Prototype Lab系统,领先的汽车零部件研发实验室管理解决方案
  • Python 引用其他文件的函数
  • 网络高级day01(Modbus 通信协议)
  • 游戏如何应对云手机刷量问题
  • RockTrack:A 3D Robust Multi-Camera-Ken Multi-Object Tracking Framework
  • iptables限制网速
  • CefSharp_Vue交互(Element UI)_WinFormWeb应用(2)---置顶和取消置顶(含示例代码)
  • JAVA虚拟机----JVM
  • 园区物业水电费收取难怎么办
  • 【Java-线程池】
  • 聚焦汽车智能化与电动化,亚洲领先的汽车工业技术博览会 2025年11月与您相约 AUTO TECH 华南展
  • 【WiFi】Qualcomm WCN6856 进入FTM操作说明
  • 初识网络编程
  • 多线程之CompletableFuture
  • 【模板进阶】模板的万能引用
  • 基于深度学习的图像描述生成
  • 机器学习 vs. 深度学习
  • Apple M3编译MAVSDK安卓平台SO库
  • 如何在Android上实现RTSP服务器
  • 2024/9/19 408大题专训之五段式指令流水线题型总结
  • fastson与jackson入门
  • Windows本地制作java证书(与jeecgboot配置本地证书ssl问题)
  • 基于vue框架的宠物领养管理系统88v55(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。
  • Python 数学建模——傅里叶变换时间序列分析
  • LeetCode 算法笔记-第 04 章 基础算法篇
  • Docker vs. containerd 深度剖析容器运行时
  • 【kafka-01】kafka安装和基本核心概念
  • CSP-J算法基础 树状结构与二叉树
  • C++笔记21•C++11•