C++:模拟实现string

目录

一:string类

二:构造函数、拷贝构造函数及析构函数

1、构造函数

2、拷贝构造函数

3、析构函数

三、实现string中对容量操作的成员函数

1、size

2、capacity

3、reserve

4、resize

5、clear

6、empty

四、string类中对象的增删查改操作

1、push_back

2、append

3、c_str

4、find

5、substr

6、insert

7、erase

五、string中重要的运算符重载

1、赋值运算符的重载

[2、流插入 <<](#2、流插入 <<)

[3、流提取 >>](#3、流提取 >>)

[4、下标访问 []](#4、下标访问 [])

[5、加等一个字符 +=](#5、加等一个字符 +=)

[6、加等字符串 +=](#6、加等字符串 +=)

[7、大于 >](#7、大于 >)

[8、等于 ==](#8、等于 ==)

[9、小于 <](#9、小于 <)

[10、大于等于 >=](#10、大于等于 >=)

[11、小于等于 <=](#11、小于等于 <=)

[12、不等于 !=](#12、不等于 !=)

六、迭代器

最后完整代码

string.h

string.c

test.c


一:string类

首先先定义一个string类

cpp 复制代码
class string
{
public:
	
private:
	char* _str = nullptr;
	size_t _size = 0;
	size_t _capacity = 0;
};

string的底层是一个个字符,所以定义一个_str 记录字符,_size用来记录这个字符串的长度,_capacity用来记录开了多少空间。


二:构造函数、拷贝构造函数及析构函数

1、构造函数

string的构造函数分为无参构造和有参构造,通过无参构造的对象会默认生成一个空字符串,因此我们可以带一个缺省值,在没有参数传递时就直接构造一空字符串

cpp 复制代码
string(const char* str = "")
	:_str(new char[strlen(str) + 1])
	, _size(strlen(str))
	, _capacity(strlen(str))
{
	strcpy(_str, str);  //将str中的内容拷贝给_str
}

在开空间时,我们需要多开一个空间,因为strlen算出的大小不包括 '\0' ,因此我们需要给 '\0' 留一个空间。


2、拷贝构造函数

拷贝构造函数是默认成员函数,如果不写编译器会自动生成,对于内置类型完成浅拷贝,对于自定义类型调用其构造函数完成拷贝。对于string来说,如果不自己写拷贝构造函数会导致浅拷贝问题。

浅拷贝会使得两个对象指向同一块空间,两个对象在析构时都会调用自己的析构函数,这样同一块空间就会被析构两次;浅拷贝一个对象的数据改变,另一个对象的数据也改变,因为它们指向同一块空间地址。 一个对象被删除后,另一个对象无效

cpp 复制代码
//浅拷贝实例
class ShallowCopyExample {
public:
    int* data;
    
    ShallowCopyExample(int value) {
        data = new int(value);
    }
    
    // 默认的拷贝构造函数是浅拷贝
    ShallowCopyExample(const ShallowCopyExample& other) = default;
    
    ~ShallowCopyExample() {
        delete data;
    }
};

int main() {
    ShallowCopyExample obj1(10);
    ShallowCopyExample obj2 = obj1;  // 浅拷贝
    
    // 问题:obj1和obj2的data指针指向同一内存
    // 当其中一个对象析构后,另一个对象的指针就悬空了
}

拷贝构造函数

cpp 复制代码
string(const string& str)
	:_str(new char[str._capacity+1])
	,_size(str._size)
	,_capacity(str._capacity)
{
    strcpy(_str, str._str);
}

上面的这种写法是比较常见的一种写法,但是我们还有一种更加简便的写法。我们可以通过已经实现了的构造函数传一个常量字符串,即下面的str._str,来创建一个临时对象,然后将这个临时对象的成员与自己交换,这样也完成了拷贝构造。

cpp 复制代码
void swap(string& s)
{
	std::swap(_str, s._str);
	std::swap(_size, s._size);
	std::swap(_capacity, s._capacity);
}
string(const string& str)
	:_str(nullptr)
	, _size(0)
	, _capacity(0)
{
	//创建一个临时对象
	string tmp(str._str);
	swap(tmp);
}

但是,为了写成这个拷贝构造函数我们还写了一个swap函数,这这么就简便了呢?

那是因为通过查阅标准库我们发现swap函数也是一个string类中提供了的函数,因此我们不仅简便了拷贝构造函数的写法,还又完成了一个函数的实现。并且,因为tmp是一个局部对象,因此在出作用域后就会自动调用析构函数,所以交换后还可以清理掉原来的空间,一举两得。

3、析构函数

我们可以使用delete直接释放掉_str的空间

cpp 复制代码
~string()
{
	delete[] _str;
	_str = nullptr;
	_size = _capacity = 0;
}

三、实现string中对容量操作的成员函数

1、size

size返回字符串有效字符的长度。我们可以直接返回其成员变量中的_szie。

cpp 复制代码
size_t size() const
{
	return _size;
}

2、capacity

capacity返回空间总大小。我们可以直接返回其成员变量中的_capacity。

cpp 复制代码
size_t capacity() const
{
	return _capacity;
}

3、reserve

reserve为字符串预留空间

cpp 复制代码
void reserve(size_t n)
{
	if (n > _capacity)
	{
		//创建一个临时变量,开n + 1个空间
		char* tmp = new char[n + 1];
		strcpy(tmp, _str);
		delete[] _str; //将原空间删除
		_str = tmp; // 将临时变量的空间给str
		_capacity = n;  // 预留多少字符给_capacity
	}
}

4、resize

resize 的功能是将有效字符的个数改成 n 个,多出的空间用字符 ch 填充。

_size < n < _capacity 先预留n大小的空间,直接用字符 填充 n - size 之间的位置,记住要在最后加上'\0'。

_size > n 直接将 n 的位置置换成'\0'。

n > _capacity 先预留 n 大小的空间,剩下的空间用字符 ch 填充,记住要在最后加上'\0'。

cpp 复制代码
void resize(size_t n, char ch)
{
	if (n > _size)
	{
		//先检查要不要扩容
		reserve(n);
		for (size_t i = _size; i < n; i++)
		{
			_str[i] = ch;
		}
		_size = n;
		_str[_size] = '\0';
	}
	else
	{
		_str[_size] = '\0';
		_size = n;
	}
}

5、clear

作用是清空有效字符

cpp 复制代码
void clear()
{
	_str[0] = '\0';
	_size = 0;
}

6、empty

empty的作用是检测字符串释放为空字符串,是返回true,否则返回false。

cpp 复制代码
bool empty() const
{
	return _size == 0;
}

四、string类中对象的增删查改操作

1、push_back

在字符串后面插字符c

cpp 复制代码
void string::push_back(char ch)
{
	if (_size == _capacity)
	{
		reserve(_capacity == 0 ? 4 : _capacity * 2);
	}
	_str[_size] = ch;
	_size++;
	_str[_size] = '\0';
}

2、append

在字符串后面追加一个字符串

cpp 复制代码
void string::append(const char* str)
{
	//先计算追加字符的个数
	size_t len = strlen(str);
	//如果 len + _size > _capacity 就需要扩容
	if (_capacity < len + _size)
	{
		//重新申请预留空间
		reserve(len + _size);
	}
	//从_str + _size出位置开始复制
	strcpy(_str + _size, str);
	_size += len;
}

3、c_str

返回一个C风格的字符串

cpp 复制代码
char* string::c_str() const
{
	return _str;
}

C风格字符串和string类字符串的区别

cpp 复制代码
void test2()
{
	string s1("hello");
	s1 += '\0';
	s1 += "dafdsaf";
	cout << s1 << endl;
	cout << s1.c_str() << endl;
}

上述代码的执行结果是:

C风格字符串以 \0 结尾, 但是string类字符串不一定以 \0 结尾,依赖size()/lenth()。

4、find

在字符串中寻找一个字符,返回第一次出现的下标

npos是string类的静态成员变量,静态成员变量要在类外定义的。我们一般将它设为公共权限,并赋值为-1。

cpp 复制代码
size_t string::find(const char sub, size_t pos) const
{
	assert(pos < _size);
	for (size_t i = pos; i < _size; i++)
	{
		if (_str[i] == sub)
			return i;
	}
	return npos;
}

在字符串中找字符串

cpp 复制代码
size_t string::find(const char* sub, size_t pos) const
{
	assert(pos < _size);
	const char* ptr = strstr(_str + pos, sub);
	if (ptr == nullptr)
	{
		return npos;
	}
	else
	{
		//指针-指针就是指针之间的距离 
		return ptr - _str;
	}
}

5、substr

它的作用是在str中从pos位置开始,截取n个字符,然后将其返回。如果不传len,则默认截取从pos开始到结尾的全部字符。 如果 pos + n > _size, 说明要截取的字符大于str的长度,则截取从pos开始到结尾的全部字符。

cpp 复制代码
string substr(size_t pos = 0, size_t len = npos) const;

string string::substr(size_t pos, size_t len) const
{
	assert(pos < _size);
	size_t reallen = len;
	//如果从pos开始截取n个字符大于_size的长度,则截取这之间的全部字符
	if (reallen == npos || reallen + pos > _size)
	{
		reallen = _size - pos;
	}
	string sub;
	for (size_t i = pos; i < reallen + pos; i++)
	{
		sub += _str[i];
	}
	return sub;
}

6、insert

在指定位置前插入一个字符

cpp 复制代码
string& insert(size_t pos, char ch);

string& string::insert(size_t pos, char ch)
{
	assert(pos <= _size);
	if (_size == _capacity)
	{
		reserve(_capacity == 0 ? 4 : _capacity * 2);
	}
	size_t end = size() + 1;
	while (end > pos)
	{
		//把pos后面的字符往后挪
		_str[end] = _str[end - 1];
		end--;
	}
	_str[pos] = ch;
	_size++;
	return *this;
}

在指定位置前插入一个字符串

cpp 复制代码
string& string::insert(size_t pos, const char* ch)
{
	assert(pos <= _size);
	//计算要插入的长度
	size_t len = strlen(ch);
	//如果要插入的长度加上原本的长度大于_capacity就需要扩容
	if (_size + len > _capacity)
	{
		reserve(_size + len);
	}
	size_t end = _size + len;
	while (pos + len <= end)
	{
		_str[end] = _str[end - len];
		end--;
	}
	//从pos位置开始复制要插入长度个字符
	strncpy(_str + pos, ch, len);
	_size += len;
	return *this;
}

7、erase

从pos开始删除n个字符

cpp 复制代码
void erase(size_t pos, size_t len = npos);

void string::erase(size_t pos, size_t len)
{
	assert(pos < _size);
	if (len == npos || len >= _size)
	{
		_str[pos] = '\0';
		_size = pos;
	}
	else
	{
		//从pos位置开始复制
		strcpy(_str + pos, _str + pos + len);
		//_size减了,对应_str字符数也少了
		_size -= len;
	}
}

五、string中重要的运算符重载

1、赋值运算符的重载

编译器默认生成的赋值重载也会导致浅拷贝,所以我们需要实现深拷贝。

cpp 复制代码
string& string::operator==(const string& str)
{
	//如果两个不是指向同一块空间
	if (this != &str)
	{
		//创建一个临时数组
		char* tmp = new char[str._capacity + 1];
		strcpy(tmp, str._str);
		delete[] _str;
		_str = tmp;
		_size = str._size;
		_capacity = str._capacity;
	}
	return *this;
}

和拷贝构造函数一样,我们也可以用简便写法来实现赋值运算符的重载

cpp 复制代码
string& string::operator=(const string& str)
{
	if (this != &str)
	{
		string tmp(str);
		swap(tmp);
	}
	return *this;
}

2、流插入 <<

流插入和流提取都要在类外定义

cpp 复制代码
ostream& operator<<(ostream& out, const string& s)
{
	for (size_t i = 0; i < s.size(); i++)
	{
		out << s[i];
	}
	return out;
}

3、流提取 >>

cpp 复制代码
	istream& operator>>(istream& in, string& s)
	{
		s.clear();
		char ch;
		ch = in.get();
		const size_t N = 32;
		char buff[N];
		size_t i = 0;
		while (ch != ' ' && ch != '\n')
		{
			buff[i++] = ch;
			if (i == N - 1)
			{
				buff[i] = '\0';
				s += buff;
				i = 0;
			}
			ch = in.get();
		}
		buff[i] = '\0';
		s += buff;
	}

4、下标访问 []

普通对象:可读可写

cpp 复制代码
char& string::operator[](size_t pos)
{
	assert(pos < _size);
	return _str[pos];
}

const对象:可读不可写

cpp 复制代码
	char& string::operator[](size_t pos) const
	{
		assert(pos < _size);
		return _str[pos];
	}

5、加等一个字符 +=

我们可以直接复用push_back来实现一个字符的加等

cpp 复制代码
string& string::operator+=(char str)
{
	push_back(str);
	return *this;
}

6、加等字符串 +=

我们可以直接复用append来实现字符串的加等

cpp 复制代码
	string& string::operator+=(const char* str)
	{
		append(str);
		return *this;
	}

7、大于 >

cpp 复制代码
bool string::operator>(const string& s) const
{
	return strcmp(_str, s._str) > 0;
}

strcmp通过比较两个字符串,如果s1 > s2,返回大于1的值;如果s1 < s2,返回小于1的值;如果s1 == s2,返回0;

8、等于 ==

cpp 复制代码
bool string::operator==(const string& s) const
{
	return strcmp(_str, s._str) == 0;
}

9、小于 <

cpp 复制代码
bool string:: operator<(const string& s) const
{
	return !(_str > s._str) && !(_str == s._str);
}

10、大于等于 >=

cpp 复制代码
bool string::operator>=(const string& s) const
{
	return !(_str < s._str);
}

11、小于等于 <=

cpp 复制代码
bool string::operator<=(const string& s) const
{
	return !(_str > s._str);
}

12、不等于 !=

cpp 复制代码
bool string::operator!=(const string& s) const
{
	return !(_str == s._str);
}

六、迭代器

迭代器作为STL的六大组件之一,它的作用十分重要。而在string中迭代器的本质就是一个char*或const char*的指针。

cpp 复制代码
typedef char* iterator;
typedef const char* const_iterator;
iterator begin()
{
	return _str;
}
const_iterator begin() const
{
	return _str;
}
iterator end()
{
	return _str + _size;
}
const_iterator end() const
{
	return _str + _size;
}

最后完整代码

string.h

cpp 复制代码
#pragma once


#include <iostream>
#include <assert.h>
//#include <string>
#include <string.h>
using namespace std;

namespace meng
{
	class string
	{
	public:
		typedef char* iterator;
		typedef const char* const_iterator;
		iterator begin()
		{
			return _str;
		}
		const_iterator begin() const
		{
			return _str;
		}
		iterator end()
		{
			return _str + _size;
		}
		const_iterator end() const
		{
			return _str + _size;
		}

		string& operator+=(char str);
		string& operator+=(const char* str);
		string& operator=(const string& str);
		char& operator[](size_t pos);
		char& operator[](size_t pos) 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 operator!=(const string& s) const;
		//
		//
		string(const char* str = "")
			:_str(new char[strlen(str) + 1])
			, _size(strlen(str))
			, _capacity(strlen(str))
		{
			strcpy(_str, str);  //将str中的内容拷贝给_str
		}
		void swap(string& s)
		{
			std::swap(_str, s._str);
			std::swap(_size, s._size);
			std::swap(_capacity, s._capacity);
		}
		string(const string& str)
			:_str(nullptr)
			, _size(0)
			, _capacity(0)
		{
			//创建一个临时对象
			string tmp(str._str);
			swap(tmp);
		}

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

		size_t size() const
		{
			return _size;
		}

		size_t capacity() const
		{
			return _capacity;
		}
		
		void reserve(size_t n);

		void resize(size_t n, char ch);

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

		bool empty() const
		{
			return _size == 0;
		}

		void push_back(char ch);
		void append(const char* str);
		char* c_str() const;
		//找一个字符串
		size_t find(const char* sub, size_t pos = 0) const;
		size_t find(const char sub, size_t pos = 0) const;
		string substr(size_t pos = 0, size_t len = npos) const;
		//insert
		//在指定位置前插入一个字符
		string& insert(size_t pos, char ch);
		//插入一个字符串
		string& insert(size_t pos, const char* ch);
		void erase(size_t pos, size_t len = npos);
	private:
		char* _str = nullptr;
		size_t _size = 0;
		size_t _capacity = 0;
		static const size_t npos;
	};
	ostream& operator<<(ostream& out, const string& s);
	istream& operator>>(istream& in, string& s);
}

string.c

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS

#include "string.h"

namespace meng
{
	const size_t string::npos = -1;
	//运算符的重载
	string& string::operator+=(char str)
	{
		push_back(str);
		return *this;
	}
	string& string::operator+=(const char* str)
	{
		append(str);
		return *this;
	}

	//string& string::operator=(const string& str)
	//{
	//	//如果两个不是指向同一块空间
	//	if (this != &str)
	//	{
	//		//创建一个临时数组
	//		char* tmp = new char[str._capacity + 1];
	//		strcpy(tmp, str._str);
	//		delete[] _str;
	//		_str = tmp;
	//		_size = str._size;
	//		_capacity = str._capacity;
	//	}
	//	return *this;
	//}
	string& string::operator=(const string& str)
	{
		if (this != &str)
		{
			string tmp(str);
			swap(tmp);
		}
		return *this;
	}

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

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

	ostream& operator<<(ostream& out, const string& s)
	{
		for (size_t i = 0; i < s.size(); i++)
		{
			out << s[i];
		}
		return out;
	}

	istream& operator>>(istream& in, string& s)
	{
		s.clear();
		char ch;
		ch = in.get();
		const size_t N = 32;
		char buff[N];
		size_t i = 0;
		while (ch != ' ' && ch != '\n')
		{
			buff[i++] = ch;
			if (i == N - 1)
			{
				buff[i] = '\0';
				s += buff;
				i = 0;
			}
			ch = in.get();
		}
		buff[i] = '\0';
		s += buff;
	}

	//
	//
	void string::reserve(size_t n)
	{
		if (n > _capacity)
		{
			//创建一个临时变量,开n + 1个空间
			char* tmp = new char[n + 1];
			strcpy(tmp, _str);
			delete[] _str; //将原空间删除
			_str = tmp; // 将临时变量的空间给str
			_capacity = n;  // 预留多少字符给_capacity
		}
	}

	void string::resize(size_t n, char ch)
	{
		if (n > _size)
		{
			//先检查要不要扩容
			reserve(n);
			for (size_t i = _size; i < n; i++)
			{
				_str[i] = ch;
			}
			_size = n;
			_str[_size] = '\0';
		}
		else
		{
			_str[_size] = '\0';
			_size = n;
		}
	}

	void string::push_back(char ch)
	{
		if (_size == _capacity)
		{
			reserve(_capacity == 0 ? 4 : _capacity * 2);
		}
		_str[_size] = ch;
		_size++;
		_str[_size] = '\0';
	}

	void string::append(const char* str)
	{
		//先计算追加字符的个数
		size_t len = strlen(str);
		//如果 len + _size > _capacity 就需要扩容
		if (_capacity < len + _size)
		{
			//重新申请预留空间
			reserve(len + _size);
		}
		//从_str + _size出位置开始复制
		strcpy(_str + _size, str);
		_size += len;
	}

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

	size_t string::find(const char sub, size_t pos) const
	{
		assert(pos < _size);
		for (size_t i = pos; i < _size; i++)
		{
			if (_str[i] == sub)
				return i;
		}
		return npos;
	}

	size_t string::find(const char* sub, size_t pos) const
	{
		assert(pos < _size);
		const char* ptr = strstr(_str + pos, sub);
		if (ptr == nullptr)
		{
			return npos;
		}
		else
		{
			//指针-指针就是指针之间的距离 
			return ptr - _str;
		}
	}

	string string::substr(size_t pos, size_t len) const
	{
		assert(pos < _size);
		size_t reallen = len;
		//如果从pos开始截取n个字符大于_size的长度,则截取这之间的全部字符
		if (reallen == npos || reallen + pos > _size)
		{
			reallen = _size - pos;
		}
		string sub;
		for (size_t i = pos; i < reallen + pos; i++)
		{
			sub += _str[i];
		}
		return sub;
	}

	string& string::insert(size_t pos, char ch)
	{
		assert(pos <= _size);
		if (_size == _capacity)
		{
			reserve(_capacity == 0 ? 4 : _capacity * 2);
		}
		size_t end = size() + 1;
		while (end > pos)
		{
			//把pos后面的字符往后挪
			_str[end] = _str[end - 1];
			end--;
		}
		_str[pos] = ch;
		_size++;
		return *this;
	}

	string& string::insert(size_t pos, const char* ch)
	{
		assert(pos <= _size);
		//计算要插入的长度
		size_t len = strlen(ch);
		//如果要插入的长度加上原本的长度大于_capacity就需要扩容
		if (_size + len > _capacity)
		{
			reserve(_size + len);
		}
		size_t end = _size + len;
		while (pos + len <= end)
		{
			_str[end] = _str[end - len];
			end--;
		}
		//从pos位置开始复制要插入长度个字符
		strncpy(_str + pos, ch, len);
		_size += len;
		return *this;
	}

	void string::erase(size_t pos, size_t len)
	{
		assert(pos < _size);
		if (len == npos || len >= _size)
		{
			_str[pos] = '\0';
			_size = pos;
		}
		else
		{
			//从pos位置开始复制
			strcpy(_str + pos, _str + pos + len);
			//_size减了,对应_str字符数也少了
			_size -= len;
		}
	}

}

test.c

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS

#include "string.h"



void test()
{
	string str("hello world");
	for (auto e : str)
		cout << e << ' ';
	cout << endl;
	//string::iterator it = str.begin()
	auto it = str.begin();
	while (it != str.end())
	{
		cout << *it << ' ';
		++it;
	}
	cout << endl;
	for (auto e : str)
	{
		e += 2;
		cout << e << ' ';
	}
	cout << endl;
	cout << str << endl;

	//string::reverse_iterator a = str.rbegin();
	auto a = str.rbegin();
	while (a != str.rend())
	{
		cout << *a << ' ';
		++a;
	}
	cout << endl;
}

namespace meng
{
	void test1()
	{
		string s1("hello world");
		cout << s1.size() << " " << s1.capacity() << endl;
		s1.reserve(16);
		cout << s1.capacity() << endl;
		//s1.resize(20, 'h');
		//cout << s1.c_str() << endl;
		//cout << s1.size() << " " << s1.capacity() << endl;
		//cout << s1.empty() << endl;
		s1.push_back('h');
		cout << s1.c_str() << endl;
		cout << s1.size() << " " << s1.capacity() << endl;
		s1.append("xxxxx");
		cout << s1.size() << " " << s1.capacity() << endl;
		cout << s1.c_str() << endl;

		cout << s1.find("xxx", 0) << endl;
		cout << s1.find('o', 0) << endl;

		string s2 = s1.substr(4, 5);
		cout << s2.c_str() << endl;

		string s3 = s1.insert(3, 'a');
		cout << s3.c_str() << endl;
		
		string s4 = s1.insert(3, "aaaaaa");
		cout << s4.c_str() << endl;
		
		s4.erase(3, 6);
		cout << s4.c_str() << endl;

		string s5 = s1; //拷贝构造
		cout << s5.c_str() << endl;
		cout << s1 << endl;
		cout << s4 << endl;
		cout << (s4 == s1) << endl;
		cout << (s4 != s1) << endl;
		cout << (s4 > s1) << endl;
		cout << (s4 < s1) << endl;


	}

	
}

void test2()
{
	string s1("hello");
	s1 += '\0';
	s1 += "dafdsaf";
	cout << s1 << endl;
	cout << s1.c_str() << endl;
}

int main()
{
	//test();
	meng::test1();
	//test2();
	
	return 0;
}
相关推荐
wuqingshun314159几秒前
经典算法 判断一个图中是否有环
java·开发语言·数据结构·c++·算法·蓝桥杯·深度优先
神仙别闹5 分钟前
基于JSP+MySQL实现用户注册登录及短信发送功能
java·开发语言·mysql
编程见习者22 分钟前
OpenCV的详细介绍与安装(一)
c++·人工智能·opencv·计算机视觉
邪恶的贝利亚25 分钟前
C++ 基础深入剖析:编译、内存与面向对象编程要点解析
开发语言·c++
ChoSeitaku31 分钟前
NO.93十六届蓝桥杯备战|图论基础-拓扑排序|有向无环图|AOV网|摄像头|最大食物链计数|杂物(C++)
c++·蓝桥杯·图论
Dream it possible!31 分钟前
CCF CSP 第36次(2024.12)(1_移动_C++)
c++·ccf csp·csp
菜狗想要变强37 分钟前
RVOS-7.实现抢占式多任务
linux·c语言·驱动开发·单片机·嵌入式硬件·risc-v
陳長生.37 分钟前
JAVA EE_初始网络原理
java·开发语言·网络·java-ee
T - mars43 分钟前
常见的爬虫算法
开发语言·javascript·ecmascript
HackerKevn1 小时前
【项目】构建高性能多线程内存池:简化版 tcmalloc 实现指南
c++·高并发内存池·tcmalloc·池化技术