模拟C++string实现

string.h

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#pragma once

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

namespace Hovl
{
	class string
	{
	public:
		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;
		}


		//string()
		//	:_str(new char[1] {'\0'})
		//	, _size(0)
		//	,_capacity(0)
		//{}
		//合并构造
		string(const char* str = "")
		{
			_size = strlen(str);
			//_capacity不包含'\0'
			_capacity = _size;
			_str = new char[_capacity + 1];
			strcpy(_str, str);
		}
		//深拷贝
		string(const string& str)
		{
			_str = new char[str._capacity + 1];
			strcpy(_str, str._str);
			_size = str._size;
			_capacity = str._capacity;
		}

		string& operator=(const string& str)
		{
			if (this != &str)
			{
				delete[]_str;
				_str = new char[str._capacity + 1];
				strcpy(_str, str._str);
				_size = str._size;
				_capacity = str._capacity;
			}
			return *this;
		}

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

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

		size_t size() const
		{
			return _size;
		}

		size_t capacity() const
		{
			return _capacity;
		}

		char& operator[](size_t pos)
		{
			assert(pos < _size);
			return _str[pos];
		}
		const char& operator[](size_t pos) const
		{
			assert(pos < _size);
			return _str[pos];
		}
		//清空string
		void clean()
		{
			_str[0] = '\0';
			_size = 0;
		}
		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);
		void insert(size_t pos, const char* str);
		void erase(size_t pos, size_t len = npos);

		size_t find(char ch, size_t pos = 0);
		size_t find(const char* str, size_t pos = 0);
		string substr(size_t pos = 0, size_t len = npos);
	private:
		char* _str = nullptr;
		size_t _size = 0;
		size_t _capacity = 0;

		static const size_t npos;
	};
	void test_string1();
	void test_string2();
	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& out, const string& s);
	istream& operator>>(istream& in, string& s);
}

代码分析

该代码实现了一个自定义的字符串类 string,位于命名空间 Hovl 中。以下是代码的主要功能和结构:

成员变量

  • _str:动态分配的字符数组,用于存储字符串内容。
  • _size:字符串的实际长度(不包含 \0)。
  • _capacity:当前分配的存储空间大小(不包含 \0)。
  • npos:静态常量,表示无效位置或最大可能值(未在代码中定义)。

成员函数

  • 迭代器支持

    • begin()end() 提供非 const 迭代器。
    • begin() constend() const 提供 const 迭代器。
  • 构造函数

    • 默认构造函数(注释掉的部分)初始化为空字符串。
    • 合并构造函数 string(const char* str = "") 接受 C 风格字符串初始化。
    • 拷贝构造函数 string(const string& str) 实现深拷贝。
  • 赋值运算符

    • operator= 实现深拷贝赋值。
  • 析构函数

    • 释放动态分配的 _str 内存。
  • 基本操作

    • c_str() 返回 C 风格字符串。
    • size()capacity() 返回字符串长度和容量。
    • operator[] 提供非 const 和 const 版本的下标访问。
  • 字符串操作

    • clean() 清空字符串。
    • reserve(size_t n) 预留空间(未实现)。
    • push_back(char ch) 追加字符(未实现)。
    • append(const char* str) 追加字符串(未实现)。
    • operator+= 重载用于追加字符或字符串(未实现)。
    • inserterase 实现插入和删除(部分未实现)。
    • find 查找字符或子串(未实现)。
    • substr 获取子串(未实现)。

非成员函数

  • 比较运算符 operator<, operator<=, operator>, operator>=, operator==, operator!=(未实现)。
  • 流操作符 operator<<operator>>(未实现)

string.c

cpp 复制代码
#include"string.h"

namespace Hovl
{
	const size_t string::npos = -1;

	void test_string1()
	{

		string s1;
		string s2("Hello World");
		cout << s1.c_str() << endl;
		cout << s2.c_str() << endl;
		//范围for
		for (auto e : s2)
		{
			cout << e << " ";
		}
		cout << endl;
		string::iterator it = s2.begin();
		while (it != s2.end())
		{
			cout << *it << " ";
			it++;
		}
		cout << endl;

		s2 += '!';
		cout << s2.c_str() << endl;

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

		s1.insert(0, 'I');
		cout << s1.c_str() << endl;
		s1.insert(0, "asdfghjkl");
		cout << s1.c_str() << endl;

		s1.erase(0 , 10);
		cout << s1.c_str() << endl;

	}

	void test_string2()
	{
		string s1;
		cin >> s1;
		cout << s1 << endl;

		string s2 = s1.substr(s1.find('2'));
		cout << s2 << endl;
	}

	void string::reserve(size_t n)
	{
		if (n > _capacity)
		{
			char* tmp = new char[n + 1];
			strcpy(tmp, _str);
			delete[]_str;
			_str = tmp;
			_capacity = n;
		}
	}
	void string::push_back(char ch)
	{
		if (_size == _capacity)
		{
			reserve(_capacity == 0 ? 4 : _capacity * 2);
		}
		_str[_size++] = ch;
		_str[_size] = '\0';
	}
	void string::append(const char* str)
	{
		size_t len = strlen(str);
		if (_size + len > _capacity)
		{
			reserve(_size + len < _capacity * 2 ? _capacity * 2 : _size + len);
		}
		strcpy(_str + _size, str);
		_size += len;
	}
	string& string::operator+=(char ch)
	{
		push_back(ch);
		return *this;
	}
	string& string::operator+=(const char* str)
	{
		append(str);
		return *this;
	}
	
	void string::insert(size_t pos, char ch)
	{
		assert(pos <= _size);
		if (_size == _capacity)
		{
			reserve(_capacity == 0 ? 4 : _capacity * 2);
		}
		int i = (int)++_size;
		for (i; i > pos; i--)
		{
			_str[i] = _str[i - 1];
		}
		_str[pos] = ch;
		_str[_size + 1] = '\0';
	}
	void string::insert(size_t pos, const char* str)
	{
		assert(pos < _size);
		size_t len = strlen(str);
		if (_size + len >= _capacity)
		{
			reserve(_size + len < _capacity * 2 ? _capacity * 2 : _size + len);
		}
		_size += len;
		int i = (int)_size;
		for (i; i >= pos + len; i--)
		{
			_str[i] = _str[i - len];
		}
		while (*str != '\0')
		{
			_str[pos] = *str;
			pos++;
			str++;
		}
		_str[_size + 1] = '\0';
	}
	void string::erase(size_t pos, size_t len)
	{
		assert(pos < _size);
		if (_size - pos < len)
		{
			_str[pos] = '\0';
		}
		else
		{
			for (int i = pos + len; i <= _size; i++)
			{
				_str[i - len] = _str[i];
			}
		}
	}

	size_t string::find(char ch, size_t pos)
	{
		assert(pos < _size);

		for (int i = pos; i < _size; i++)
		{
			if (_str[i] == ch)
			{
				return i;
			}
		}
		return npos;
	}
	size_t string::find(const char* str, size_t pos)
	{
		assert(pos < _size);
		const char* ptr = strstr(_str + pos, str);
		if (ptr == nullptr)
		{
			return npos;
		}
		else
		{
			return ptr - str;
		}
	}
	string string::substr(size_t pos, size_t len)
	{
		assert(pos < _size);
		if (len > _size - pos)
		{
			len = _size - pos;
		}
		string sub;
		sub.reserve(len);
		for (int i = 0; i < len; i++)
		{
			sub += _str[pos + i];
		}
		return sub;
	}
	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 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 strcmp(s1.c_str(), s2.c_str()) == 0;
	}
	bool operator!=(const string& s1, const string& s2)
	{
		return !(s1 == s2);
	}

	ostream& operator<<(ostream& out, const string& s)
	{
		for (auto ch : s)
		{
			out << ch;
		}
		return out;
	}
	istream& operator>>(istream& in, string& s)
	{
		s.clean();

		const int N = 256;
		char buff[N];
		int i = 0;
		char ch = cin.get();
		while (ch != ' ' && ch != '\n')
		{
			buff[i++] = ch;
			if (i == N - 1)
			{
				buff[i] = '\0';
				s += buff;
				i = 0;
			}
			ch = cin.get();
		}
		if (i > 0)
		{
			buff[i] = '\0';
			s += buff;
		}
		return in;
	}
}

代码分析:自定义字符串类实现

该代码实现了一个自定义字符串类 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;
    }
}
  • 当需要扩容时,分配新内存并复制原有内容。
  • 容量不足时按指数增长(默认扩容为原容量的2倍)。

追加字符/字符串

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

void string::append(const char* str) {
    size_t len = strlen(str);
    if (_size + len > _capacity) {
        reserve(_size + len < _capacity * 2 ? _capacity * 2 : _size + len);
    }
    strcpy(_str + _size, str);
    _size += len;
}
  • push_back 处理单字符追加,自动检查容量。
  • append 处理C风格字符串,动态调整容量。

插入操作

cpp 复制代码
void string::insert(size_t pos, char ch) {
    assert(pos <= _size);
    if (_size == _capacity) {
        reserve(_capacity == 0 ? 4 : _capacity * 2);
    }
    for (int i = (int)++_size; i > pos; i--) {
        _str[i] = _str[i - 1];
    }
    _str[pos] = ch;
}

void string::insert(size_t pos, const char* str) {
    assert(pos < _size);
    size_t len = strlen(str);
    if (_size + len >= _capacity) {
        reserve(_size + len < _capacity * 2 ? _capacity * 2 : _size + len);
    }
    _size += len;
    for (int i = (int)_size; i >= pos + len; i--) {
        _str[i] = _str[i - len];
    }
    while (*str) {
        _str[pos++] = *str++;
    }
}
  • 字符插入通过后移元素实现。
  • 字符串插入需处理内存重叠问题。

运算符重载

比较运算符

cpp 复制代码
bool operator<(const string& s1, const string& s2) {
    return strcmp(s1.c_str(), s2.c_str()) < 0;
}
// 其他比较运算符类似...
  • 基于 strcmp 实现字典序比较。

流操作符

cpp 复制代码
ostream& operator<<(ostream& out, const string& s) {
    for (auto ch : s) out << ch;
    return out;
}

istream& operator>>(istream& in, string& s) {
    s.clean();
    char buff[256];
    // 分批读取输入以避免缓冲区溢出
    // ...
    return in;
}
  • 输出遍历字符,输入采用缓冲区块读取。

使用示例

cpp 复制代码
void test_string1() {
    string s2("Hello World");
    s2 += '!';          // 追加字符
    s2 += "123";        // 追加字符串
    s2.insert(0, 'X');  // 头部插入
    s2.erase(0, 5);     // 删除子串
}

改进建议

  1. 异常安全new 操作可能失败,需处理异常。
  2. 移动语义:可增加移动构造函数和移动赋值优化性能。
  3. Unicode支持:当前实现仅处理单字节字符。

该实现模拟了标准库 std::string 的基础功能,适合学习字符串类的底层设计原理。

相关推荐
~央千澈~2 小时前
人工智能AI算法推荐之番茄算法推荐证实其算法推荐规则技术解析·卓伊凡
人工智能·算法·机器学习
oioihoii2 小时前
C++内存安全方案前沿研究
c++·安全·mfc
羚羊角uou2 小时前
【数据结构】常见排序
数据结构·算法·排序算法
十五年专注C++开发2 小时前
QProcess在Windows下不能正常启动exe的原因分析
开发语言·c++·windows·qprocess·createprocess
无限进步_2 小时前
C++多态全面解析:从概念到实现
开发语言·jvm·c++·ide·git·github·visual studio
无限进步_2 小时前
C++ STL容器适配器深度解析:stack、queue与priority_queue
开发语言·c++·ide·windows·算法·github·visual studio
byzh_rc2 小时前
[算法设计与分析-从入门到入土] 分治法
算法
拉拉拉拉拉拉拉马2 小时前
感知机(Perceptron)算法详解
人工智能·python·深度学习·算法·机器学习
falldeep2 小时前
LeetCode高频SQL50题总结
数据结构·数据库·sql·算法·leetcode·职场和发展