如何做企业微信,seo是如何优化,网站建设程序流程图,wordpress page templates #x1f339;个人主页#x1f339;#xff1a;喜欢草莓熊的bear #x1f339;专栏#x1f339;#xff1a;C入门 前言 hello #xff0c;大家又来跟着bear学习了。一起奔向更好的自己#xff0c;上篇博客已经讲清楚了string的一些功能的使用。我们就实现一些主要的功… 个人主页喜欢草莓熊的bear 专栏C入门 前言 hello 大家又来跟着bear学习了。一起奔向更好的自己上篇博客已经讲清楚了string的一些功能的使用。我们就实现一些主要的功能。 一、实现string的思路 头文件
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#includeiostream
#includestring
#includeassert.h
using namespace std; 我们先写一个大框架我的是放在了rose这个命名空间里面。定义完了成员变量还给了缺省值。
namespace rose
{class string
{
public:private:
char* _strnullptr;
size_t _size0;
size_t _capacity0;
}} 因为成员变量不是自定义类型所以我们需要自己写构造和析构函数。 构造函数
如果没有传参数我们就给一个”“有的话我们就拷完成深拷贝浅拷贝会导致内存问题。再原有基础上多开一个空间是方便储存\0。
string(const char* str)//构造函数
{_size strlen(str);_capacity _size;_str new char[_capacity 1];//储存\0strcpy(_str, str);//参数1是destination目标 参数2是source源
}//还是一样深拷贝
string(const string s)
{_str new char[s._capacity 1];strcpy(_str, s._str);_size s._size;_capacity s._capacity;
}
析构函数
我们释放我们之前申请的空间如果申请了就释放没有就不释放空间。
~string()//析构
{if (_str){delete[] _str;_str nullptr;_size _capacity 0;}
} size和capacity
很简单不用多说
size_t size()const//元素个数
{return _size;
}size_t capacity()const//容量
{return _capacity;
} 观察发现string的这些接口都是使用迭代器的所以我们使用typedef 重定义一下 char* 和 const char*。 typedef char* iterator;//重定义
typedef const char* const_iterator; begin和end
begin返回最开始的位置也将是首元素end是最后一个元素。std库里面提供了两种我们也实现两种。
iterator begin()//因为成员函数所以第一个参数不用写默认指向this指针
{return _str;
}const_iterator begin()const
{return _str;
}iterator end()
{return _str _size;
}const_iterator end()const
{return _str _size;
} 拷贝构造函数
浅拷贝会导致内存释放问题所以还是采用深拷贝。
string(const string s)
{_str new char[s._capacity 1];strcpy(_str, s._str);_size s._size;_capacity s._capacity;
} clear和c_str
clear是清除动态数组里面的字符只剩\0c_str是返回c语言风格的。 这两个也很简单实现
void clear()//清楚字符串
{_str[0] \0;_size 0;
}const char* c_str() const//就是单纯返回C语言的风格比如string类型直接使用strcmp不安全。
{return _str;
} 重载operator 和 operator []
先看库里面string的”“ 与 ”[]“。 重载[]也就是返回下标元素注意的是要传合法下标注意一下越界
char operator[](size_t pos)//【】
{assert(pos _size);return _str[pos];
}const char operator[](size_t pos)const
{assert(pos _size);return _str[pos];
} 重载”“分为两种一个是传统写法还有一个现代写法。
传统写法就是什么都考自己来完成我们是举例把s2赋值给s1。
先把之前原来数组里面的空间给释放再重新申请s2的空间1为了储存\0。接着把s2的成员变量拷贝给s1的成员变量.空间大小申请好了我们就把s2的字符复制给s1.这里调用strcpy。再判断一下s1和s2是否相等。
传统赋值
s1 s2
string operator(const string s)
{if (this ! s)//this指针是地址所以需要取s的地址来比较{delete[]_str;_str new char[s._capacity 1];_size s._size;_capacity s._capacity;strcpy(_str, s._str);}return *this;
} 现代写法大部分考编译器来做。
借助拷贝构造完成中间对象的创建并且把中间对象和this指针的对象进行交换指向的空间数据个数容量又因为tmp出来作用域会销毁所以还顺便把this之前的空间也给销毁了。
void swap(string str)
{std::swap(_str, str._str);//std::swap是库里面的std::swap(_size, str._size);std::swap(_capacity, str._capacity);
}//借助拷贝构造完成中间对象的创建并且把中间对象和this指针的对象进行交换指向的空间数据个数容量
//又因为tmp出来作用域会销毁所以还顺便把this之前的空间也给销毁了。
string operator(const string s)//现代赋值
{if (this ! s)//this指针是地址所以需要取s的地址来比较{string tmp(s);swap(tmp);}return *this;
}//s1 s2
string operator(string tmp)//直接使用临时对象来接收s2的值//因为是传值传参使用会调用拷贝构造//这里判断他们相等意义不大可判 可不判
{swap(tmp);return *this;
} 我们这些写的都是内联函数频繁调用且代码不长的。 reserve、push_back和append
reserve目的扩容首先判断需不需要扩容。我们采用深拷贝把原数组里面的内容cpy到临时数组tmp里面。
push_back目的插入字符分为容量有没有满没满就直接尾插满了扩容后继续尾插。一般扩容是按照两倍来的。
append目的是在末尾加入字符串和push_back一样是否需要扩容因为是字符串所以我们采用strcpy更快但是初始位置是_strsize。
void string::reserve(size_t n 0)//扩容函数
{if (n _capacity){char* tmp new char[n 1];//多一个用来装\0strcpy(tmp, _str);delete[]_str;_str tmp;_capacity n;}
}void string::push_back(char ch)
{if (_capacity _size){reserve(_capacity 0 ? 4 : 2 * _capacity);}_str[_size] ch;_str[_size] \0;
}void string::append(const char* str)
{size_t len strlen(str);if (_size len _capacity){// 大于2倍需要多少开多少小于2倍按2倍扩reserve(_sizelen 2 * _capacity ? _size len :2*_capacity);}strcpy(_str _size, str);//因为append是要实现在字符串后面加字符串这里是_str数组首元素_size正好拷贝的时候覆盖率旧的\0_size len;
}
insert和erase
insert这里是在pos位置插入一个字符。
erase是删除从第pos位置后面的所有字符。
void string::insert(size_t pos, const char* str)
{assert(pos _size);size_t len strlen(str);if (_size _capacity){reserve(_capacity 0 ? 4 : 2 * _capacity);}size_t end _size 1;while (end pos){_str[end] _str[end - 1];--end;}for (size_t i 0;i len;i)//{_str[pos i] str[i];}_size len;
}void 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 len pos;i _size;i){_str[i - len] _str[i];--_size;}//_size-len;}
}
find和substr
find写了两个一个是查找第一个字符还有查找字符串。
substr拷贝pos到len指定区域的字符。
size_t string::find(char ch, size_t pos)
{assert(pos _size);for (size_t 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* tmp strstr(_str pos, str);//str是比较字符串的函数。if (tmp nullptr){return npos;}else{return tmp - _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 (size_t i 0;i len;i){sub[i] _str[pos i];}return sub;
}operator
分为字符和字符串可以直接调用插入函数。
string string::operator(char ch)//这个函数是string类的呀用域名修饰符修饰了,对的这个函数实际还是一个成员函数
{push_back(ch);return *this;//
}
string string::operator(const char* str)
{append(str);return *this;//
}
operator 、、、 、、!
我们可以通过实现其中两个来通过他们的逻辑关系来实现其他的。
我这里是实现了operator和operator调用strcmp来实现的。
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);
}operator 和
operator 函数接受一个 ostream 类型的对象作为参数并返回该对象本身。它遍历输入的字符串中的每个字符并将其写入到输出流中。
operator 函数则接受一个 istream 类型的对象作为参数并返回该对象本身。它首先清空输入字符串然后逐个读取输入流中的字符直到遇到空格或换行符为止。如果在读取过程中遇到了超过 N-1 个字符则会将前面的部分存储到缓冲区中并将剩余部分直接存储到输入字符串中。最后它将读取到的所有字符存储到输入字符串中并返回输入流本身。
ostream operator(ostream out, const string s)
{for (auto ch : s){out ch;}return out;
}
istream operator(istream in, string s)//
{s.clear();const int N 256;char buff[N];int i 0;char ch;//in ch;//使用inch 默认空格为分格符读取不到ch in.get();//给次对一个字符什么都读。while (ch ! ch ! \n){buff[i] ch;if (i N - 1){buff[i] \0;s buff;i 0;}//in ch;ch in.get();}if (i 0)//提前遇到“ ”或者 “\n”;{buff[i] \0;s buff;}return in;
} 总结 感谢大家的支持我会继续努力创造出更好的博客。