STL----string模拟实现


string成员函数:
find():查找字符

int main() {
	string url = "https://www.baidu.com/xxx/120494/56465/";
	
	//协议
	size_t pos1 = url.find(':');
	if (pos1 != string::npos) {
		cout << url.substr(0, pos1) << endl;
	}
	
	//网址
	size_t pos2 = url.find('/', pos1 + 3);
	if (pos2 != string::npos) {
		cout << url.substr(pos1 + 3, pos2 - pos1 - 3) << endl;
	}

	//资源
	size_t pos3 = pos2;
	cout << url.substr(pos3) << endl;

	return 0;
}

简单string实现(传统写法)

如果有人要你模拟实现一个简单的string,那主要要看的就是你对深浅拷贝的理解,就是实现类的默认成员函数。

#include <iostream>
#include <cassert>
using namespace std;

class String {

public:

	//构造函数 全缺省 + 一个参数
	//需要注意的是要多开一个字节的空间给 \0  并且""该字符串具有一个'\0'
	String(const char* str = "")
		:_str(new char[strlen(str) + 1])
	{
		strcpy(_str, str);
	}

	//析构函数
	~String() {
		if (_str) {
			delete[] _str;
			_str = nullptr;
		}
	}

	//拷贝构造 如果不写 编译器默认生成浅拷贝 
	//对于指针类型浅拷贝 程序会在析构时将同一块空间析构两次崩掉
	//并且因为指向同一块内存区域 会导致一个对象数据修改 影响到另一个对象的数据也被修改
	/*String(const String& s)
		:_str(new char[strlen(s._str) + 1]) {
		strcpy(_str, s._str);
	}*/

	//现代写法
	String(const String& s)
		: _str(nullptr)
	{
		String tmp(s._str);
		swap(_str, tmp._str);
	}

	//赋值运算符(两给对象都已经存在)
	//返回左值的引用 是为了连续赋值
	//如果不写 编译器会默认生成浅拷贝的赋值重载 浅拷贝必然产生和拷贝构造相同的问题
	
	//String& operator=(const String& s) {
	//	//避免自己给自己赋值
	//	if (this != &s) {
	//		//赋值时两个空间大小需要一致 但并不知道是否一致 所以直接释放掉 开一个满足的新空间进行复制
	//		delete[] _str;
	//		_str = new char[strlen(s._str) + 1];
	//		strcpy(_str, s._str);
	//	}
	//	return *this;
	//}
	
	//现代写法
	String& operator=(String s) {
		if (this != &s) {
			swap(_str, s._str);
		}
		return *this;
	}

	//返回c格式的字符数组
	const char* c_str() {
		return _str;
	}

	//重载[]运算符
	//为了可读可写 应该返回引用
	char& operator[](size_t i) {
		//使其越界直接崩掉
		assert(i < size());
		return _str[i];
	}

	size_t size() {
		return strlen(_str);
	}

private:
	char* _str;
};

关于拷贝构造和赋值函数,可以使用现代写法(一种思想)

拷贝构造现代写法

String(const String& s)
		: _str(nullptr)
	{
		String tmp(s._str);
		swap(_str, tmp._str);
	}

赋值函数的现代写法

String& operator=(String s) {
	if (this != &s) {
		swap(_str, s._str);
	}
	return *this;
}

具有增删查改接口的string实现

在简单string类中完善其他接口

#include <iostream>
#include <cassert>
using namespace std;

class String {
public:

	//迭代器可以理解为类似指针的类型,有的是指针 有的不是指针
	typedef char* iterator;
	typedef const char* const_iterator;

	String(const char* str = "") {
		//strlen有消耗  这样写可以少调用
		_size = strlen(str);
		_capacity = _size;
		_str = new char[_size + 1];
		strcpy(_str, str);
	}

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

	void Swap(String& s) {
		swap(_str, s._str);
		swap(_size, s._size);
		swap(_capacity, s._capacity);
	}

	String(const String& s)
		: _str(nullptr),
		_size(0),
		_capacity(0)
	{
		String tmp(s._str);
		Swap(tmp);
	}

	String& operator=(String s) {
		if (this != &s) {
			Swap(s);
		}
		return *this;
	}

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

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

	//返回有效字符数量
	size_t size() const {
		return _size;
	}

	//返回有效字符容量
	size_t capacity() const {
		return _capacity;
	}

	//迭代器开始位置 这里可以理解为首元素的位置
	iterator begin() {
		return _str;
	}

	const_iterator begin()const {
		return _str;
	}

	//迭代器结束位置 这里可以理解为'\0'的位置
	iterator end() {
		return _str + _size;
	}

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

	//为字符串预留空间
	void reserve(size_t n) {
		if (n > _capacity) {
			char* tmp = new char[n + 1];
			strcpy(tmp, _str);
			delete[] _str;
			_str = tmp;
			_capacity = n;
		}
	}

	//尾插字符
	void push_back(char ch) {
		insert(_size, ch);
	}

	//追加字符串
	void append(const char* str) {
		size_t len = strlen(str);
		if (_size + len > _capacity) {
			reserve(_size + len);
		}

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

	//插入字符
	void insert(size_t pos, const char ch) {
		assert(pos <= _size);

		//检查容量
		if (_size == _capacity) {
			//当前容量空的话开两个空间
			size_t newCapacity = _capacity == 0 ? 2 : _capacity * 2;
			reserve(newCapacity);
		}
		
		//要注意i最后会减为-1,无符号-1是最大值 还会判断为大于pos 
		//变成了死循环  解决办法是i使用int 然后pos也强转为int后比较
		for (int i = _size ; i >= (int)pos; --i) {
			_str[i + 1] = _str[i];
		}
		_str[pos] = ch;
		++_size;
	}

	//插入字符串
	void insert(size_t pos, const char* str) {
		assert(pos <= _size);

		size_t len = strlen(str);
		if (_size + len > _capacity) {
			reserve(_size + len);
		}

		//要注意i最后会减为-1,无符号-1是最大值 还会判断为大于pos 
		//变成了死循环  解决办法是i使用int 然后pos也强转为int后比较
		int end = _size;
		while (end >= (int)pos) {
			_str[end + len] = _str[end];
			--end;
		}

		//拷贝len个 就不会 把\0拷过来到中间
		strncpy(_str + pos, str, len);
		_size += len;
	}

	//删除
	String& erase(size_t pos = 0, size_t len = npos) {
		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;
		}
		return *this;
	}

	//指定位置开始查找第一次出现的字符
	size_t find(char c, size_t pos = 0) {
		assert(pos < _size);
		for (size_t i = pos; i < _size; ++i) {
			if (_str[i] == c) {
				return i;
			}
		}
		return npos;
	}

	//查找第一次出现的子串
	size_t find(const char* str, size_t pos = 0) {

		char* ret = strstr(_str + pos, str);
		if (ret != nullptr) {
			return npos;
		}

		//返回下标
		return ret - _str;
	}

	//字符串追加
	String& operator+=(const char* str) {
		append(str);
		return *this;
	}

	String& operator+=(char ch) {
		push_back(ch);
		return *this;
	}

	String& operator+=(const String& s) {
		append(s._str);
		return *this;
	}

	//将有效字符的个数改为n个,多出的空间用字符c填充
	void resize(size_t n, char c) {

		//需要的空间小于当前容量 就不需要开空间了
		if (n < _capacity) {
			_str[n] = '\0';
			_size = n;
		}
		else {
			//需要的空间大于当前容量,则开新空间
			if (n > _capacity) {
				reserve(n);
			}

			//从之前结尾开始填充
			for (size_t i = _size; i < n; ++i) {
				_str[i] = c;
			}
			_size = n;
			_str[_size] = '\0';
		}
	}

	//运算符重载
	bool operator>(const String& s) {
		int ret = strcmp(_str, s._str);
		return ret > 0;
	}
	bool operator==(const String& s) {
		int ret = strcmp(_str, s._str);
		return ret == 0;
	}
	bool operator<(const String& s) {
		return !(*this >= s);
	}
	bool operator>=(const String& s) {
		return *this > s || *this == s;
	}
	bool operator<=(const String& s) {
		return !(*this > s);
	}
	bool operator!=(const String& s) {
		return !(*this == s);
	}

private:
	char* _str;
	size_t _size;//已经存在的有效字符个数
	size_t _capacity;//可以容纳的有效字符个数  不包含'\0'

	static const size_t npos;//默认无符号整型的最大值
};

const size_t String::npos = -1;

//重载输出
ostream& operator<<(ostream& out, String& s) {
	for (size_t i = 0; i < s.size(); ++i) {
		out << s[i];
	}
	return out;
}

//重载输入
istream& operator>>(istream& in, String& s) {
	while (1) {
		char c;
		//使用in >> c,不会读到空格 遇到空格认为是结束
		c = in.get();

		//如不判断是否为空格 就是getline 读取一行
		//if(c=='\n'){
		if (c == ' ' || c == '\n') {
			break;
		}
		else {
			s += c;
		}
	}
	return in;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我来帮您解答这个问题。 首先,我们需要定义一个学生类,包含学生的基本信息以及相关成绩信息: ```c++ #include <string> #include <vector> #include <iostream> using namespace std; class Student { public: string name; // 学生姓名 int age; // 学生年龄 vector<int> scores; // 存储学生各门课的成绩 // 构造函数 Student(string name, int age) : name(name), age(age) {} // 计算平均成绩 double avg_score() const { double sum = 0.0; for(int score : scores) { sum += score; } return scores.empty() ? 0.0 : sum / scores.size(); } // 输出学生信息 friend ostream& operator<<(ostream& os, const Student& student) { os << "Name: " << student.name << ", Age: " << student.age << ", Scores: "; for(int score : student.scores) { os << score << " "; } os << ", Avg Score: " << student.avg_score(); return os; } }; ``` 接下来,我们需要模拟上课过程,即随机生成学生的成绩,并将其存储到容器中: ```c++ #include <random> // 模拟上课过程,随机生成学生的成绩 void simulate_class(vector<Student>& students) { // 随机数生成器 random_device rd; mt19937 gen(rd()); uniform_int_distribution<> dis(0, 100); // 遍历学生,生成成绩 for(auto& student : students) { for(int i = 0; i < 5; i++) { student.scores.push_back(dis(gen)); } } } ``` 最后,我们需要使用STL库的相关容器对数据进行存储,并将数据保存到文件中: ```c++ #include <fstream> // 从文件中读取学生信息 void read_students(const string& filename, vector<Student>& students) { ifstream fin(filename); string name; int age, score; while(fin >> name >> age) { Student student(name, age); while(fin >> score) { student.scores.push_back(score); } students.push_back(student); } fin.close(); } // 将学生信息保存到文件中 void save_students(const string& filename, const vector<Student>& students) { ofstream fout(filename); for(const auto& student : students) { fout << student.name << " " << student.age << " "; for(int score : student.scores) { fout << score << " "; } fout << endl; } fout.close(); } int main() { vector<Student> students; // 从文件中读取学生信息 read_students("students.txt", students); // 模拟上课过程 simulate_class(students); // 将学生信息保存到文件中 save_students("students.txt", students); // 输出学生信息 for(const auto& student : students) { cout << student << endl; } return 0; } ``` 以上就是基于C++定义一个学生类,实现上课过程的模拟和平时成绩的计算,应用STL库的相关容器对数据进行存储,程序数据可以保存到文件中,开始程序时自动读取的全部代码。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值