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

C++中string的模拟和实现

目录

1.模拟实现string基本的定义与构造

2.模拟实现string的各种函数

1.扩容reserve()

2.push_back()尾插 

3.resize()对元素数量进行修改 

4.append()在末端插入字符串

 5.find()从pos处开始查找字符,并返回第一次出现的位置

6.insert()在pos位置插入一个字符

7.erase()删除pos上的元素并返回

8.str()、size()、capacity()、empty()获取数据存放的位置,数量,容器的容量以及判空 

3.迭代器

1.begin() 

2.end() 

4.各种运算符的重载 

1.由于大于小于等判断运算符基本可以复用,这里只写出>=、<=、==

 2.[]运算符

3.<<,>>流插入流提取运算符


 

1.模拟实现string基本的定义与构造

c++中string是STL容器的一种,其数据类型为字符类型,所以,我们在定义中需要用char* _str来存放数据,用size_t来定义两个变量分别为_size、_capacity,其中_size为存放的数据数量,_capacity来表示我们能够存放多少数据,也就是容量;

class string
{
    pubilc:
        :
        :
        :
    pravite:
    char*  _str;    //为了区分成员变量,⼀般习惯上成员变量
    size_t _size;   // 会加⼀个特殊标识,如_ 或者 m开头
    size_t _capacity;
};

 string的定义可以有多种,例如

string str1;
string str2("efgh");
string str3(str2);//拷贝构造

 所以,我们也得实现其多种构造函数,以及析构函数

 

class string
{
    pubilc:
        string()
        {
            _str=nullptr;
            _size=0;
            _capacity=0;
        }
        string(const char* str)
	       :_size(strlen(str))
        {
	        _capacity = _size;
	        _str = new char[_size + 1];
	        strcpy(_str, str);
        }
        string(const string& str)
        {
            _str = new char[str._capacity + 1];
            _capacity = str._capacity;
            _size = str._size;
        }
        ~string()
        {
            delete []_str;
            _size=0;
            _capacity=0;
            _str=nullptr;
        }
    pravite:
    char*  _str;   
    size_t _size;  
    size_t _capacity;
};

 

2.模拟实现string的各种函数

我们已经对string 有了基本的了解,现在我们来实现string的各种函数的模拟实现

1.扩容reserve()

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

2.push_back()尾插 

尾插就是在数据最末端,也就是_str[_size]处插入一个字符

void string::push_back(char c)
{
	if (_size + 1 > _capacity)                        //尾插前需检查_capacity是否等于_size
	{
		reserve(_capacity == 0 ? 4 : _capacity * 2);  //也就是是否“满了”
	}
	_str[_size] = c;                                  //如果满了则扩容,一般为了不浪费空间
	_size++;
	_str[_size] = '\0';                               //选择扩容至原来的2倍
}

3.resize()对元素数量进行修改 

当n小于_size时,我们会进行尾删,删到只剩n个元素,并且把元素个数进行修改

当n大于_size且小于_capacity时,我们补全元素到n位,多余的这些元素用c来替代,然后修改_size 

 当n大于_capacity时,我们先进行扩容,再把元素补全到n位,然后修改_size

void string::resize(size_t n, char c )
{
	if (n > _size)                        //当n大于_size时小于_capacity时,
	{
		reserve(n);                       //reserve是不会进行扩容的
		for (size_t i = _size; i < n; i++)
		{
			_str[i] = c;
		}
		_size = n;
		_str[_size] = '\0';
	}
	else
	{
		_str[n] = '\0';                    //小于_size时,只需直接将n处改为\0
		_size = n;
	}
}

4.append()在末端插入字符串

void string::append(const char* str)
{
	size_t len = strlen(str);
	if (_size + len > _capacity)            //“满了”则扩容
	{
		size_t newcapacity = 2 * _capacity;
		if (_size + len > 2 * _capacity)
		{
			newcapacity = _size + len;
		}
		reserve(newcapacity);
	}
	strcpy(_str + _size, str);
	_size += len;
}

 5.find()从pos处开始查找字符,并返回第一次出现的位置

size_t string::find(char c, size_t pos=0) const
{
    assert(pos < _size);
	for (size_t i = pos; i < _size; i++)
	{
		if (_str[i] == c)
		{
			return i;
		}
	}
	return npos;                    //由于我们需要返回size_t类型的数据,当查找不到时无法返                            
}                                   //回位置,所以我们需要在成员变量里定义一个npos,并给出
                                    //缺省值-1

6.insert()在pos位置插入一个字符

 string::insert(size_t pos, char c)
{
	assert(pos <= _size);
	if (_size + 1 > _capacity)                //“满了”扩容
	{
		size_t newcapacity = 2 * _capacity;
		reserve(newcapacity);
	}
	size_t end = _size + 1;
	while (end > pos - 1)
	{
		_str[end] = _str[end - 1];
		end--;
	}
	_str[pos - 1] = c;
}

7.erase()删除pos上的元素并返回

string& string::erase(size_t pos, size_t len)
{
	if (len >= _size-pos)
	{
		_str[pos] = '\0';
		_size = pos;
	}
	else
	{
		size_t end = pos + len;
		while (end <= _size)
		{
			_str[end - len] = _str[end];
			end++;
		}
		_size -= len;
	}
        return *this;
}

8.str()、size()、capacity()、empty()获取数据存放的位置,数量,容器的容量以及判空 

const char* str()const
{
    return _str;
}
size_t size()const
{
    return _size;
}
size_t capacity()const
{
    return _capacity;
}
bool empty()const
{
    return _size == 0;
}

3.迭代器

1.begin() 

iterator begin()
{
    return _str;
}

2.end() 

iterator end()
{
    return _str + _size;
}

4.各种运算符的重载 

1.由于大于小于等判断运算符基本可以复用,这里只写出>=、<=、==

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

 2.[]运算符

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

3.<<,>>流插入流提取运算符

在开始前,由于对于已经有元素的string对象,不能直接流提取,我们可以先调用一个clear函数再进行流提取

并且流插入和流提取函数只能写在类的外面或者使用友元函数写在类的里面,写在类外面的原因是写在类里面this指针会默认抢占第一个参数的位置,而第一个参数是out

clear()

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

s不能加上const,因为s需要被读写 

ostream& bit::operator<<(ostream& _cout,  bit:: string& s)
{
	for ( auto a : s )
	{
		cout << a;
	}
	return cout;
}

流提取时,为了代码的效率,防止大量扩容,我们需要设置一个buff数组来减少扩容的次数

在一些编译器里,buff数组是确实存在的,可以通过监视窗口看见 

istream& bit :: operator>>(istream& _cin, bit::string& s)
{
	s.clear();
	const int N = 1024;
	char buff[N];
	int i = 0;
	char ch = cin.get();
	while (ch != ' ' && ch != '\0')
	{
		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 cin;
}

 

 

 

 

 

 

 

 

 

 

 

 


http://www.kler.cn/a/582752.html

相关文章:

  • java登神之阶之顺序表
  • 桂链:什么是区块链排序服务?
  • macOS 安装 Homebrew、nvm 及安装切换 node 版本
  • Java项目启动后无日志输出
  • 动态规划详解(四):线性DP原理深度剖析
  • Node.js 技术原理分析系列5——理解 Node.js 中的 ABI 稳定
  • 抖音全案代运营公司-品融电商
  • FI模块功能范围的基本概念、用途、配置介绍
  • PHP版多语言多商家海外商城源码开源无加密
  • Ragflow技术栈分析及二次开发指南
  • visual studio配置opencv
  • 【DevOps】通过 Azure DevOps 部署启用私有端点的应用服务
  • Flink-学习路线
  • Java volatile 关键字详解
  • Pandas教程:数据分析利器 - 从入门到精通
  • AI大模型的地址治理ETL方案
  • MySQL常用函数详解及SQL代码示例
  • BLIP-2:使用冻结图像编码器和大型语言模型进行语言-图像预训练
  • Linly-Talker:开源数字人框架的技术解析与影响
  • 容器编排革命:从 Docker Run 到 Docker Compose 的进化之路20250309