网站内容怎么编辑,wordpress模板页,输入文字生成图片app,建设官方网站怎么修改预留手机我们接着上一篇【C】string类 #xff08;模拟实现详解 上#xff09;-CSDN博客继续对string模拟实现。从这篇内容开始#xff0c;string相关函数的实现就要声明和定义分离了。
1.reserve、push_back和append
在string.h的string类里进行函数的声明。
void reserve(size_… 我们接着上一篇【C】string类 模拟实现详解 上-CSDN博客继续对string模拟实现。从这篇内容开始string相关函数的实现就要声明和定义分离了。
1.reserve、push_back和append
在string.h的string类里进行函数的声明。
void reserve(size_t n); //扩容
void push_back(const char x);//尾插字符
void append(const char* str);//尾插字符串在string.cpp中进行函数的实现。这个文件要包含include string.h同样用命名空间。
n小于_capacity的情况都默认为空间不变n大于_capacity扩容。
#include string.h
namespace lyj //命名空间
{void string::reserve(size_t n){if (n _capacity){char* temp new char[n 1];//多开一个留给\0strcpy(temp, _str);//把_str里的数据拷贝到新空间delete[] _str; //释放旧空间_str temp; //让_str指向新空间_capacity n; //更新_capacity的值}}
}
reserve实现好了push_back可以直接复用reserve的扩容。还是在命名空间里实现。
void string::push_back(const char x)//尾插字符
{if (_size _capacity)//两者相等时空间不够{//扩容2倍扩,如果_capacity为0就直接给4string::reserve(_capacity 0 ? 4 : _capacity * 2);}_str[_size] x;//插入字符_size;//更新_size的值 _str[_size] \0;//末尾一定是\0
}
新插入的x会把原来末尾的\0覆盖所以我们要在新末尾加上\0。
append也是需要复用reserve。push_back是2倍扩容append我们就要分情况决定扩容大小了。
void string::append(const char* str)//尾插字符串
{size_t len strlen(str);//计算要插入的字符串的长度if (_size len _capacity)//如果空间不够扩容{//如果插入的字符串特别长2倍扩就会扩容频繁所以在这里判断一下reserve(_size len _capacity * 2 ? _size len : _capacity * 2);}strcpy(_str _size, str);//从原字符串的\0出开始拷贝新的str_size len; //更新_size的大小
}
如果插入的字符串特别长2倍扩就会扩容频繁所以如果原字符串长度加上插入的新字符串长度比_capacity的两倍要大我们就不以2倍扩容直接扩到原字符串长度加上插入的新字符串长度那么大反之还是以2倍扩。 在test.cpp中测试一下。
void test2()
{string s1(hello world);s1.push_back(x);s1.append(yyyyyyyyyyyyyyyyyyy);cout s1.c_str() endl;
}
int main()
{lyj::test2(); //指定命名空间调用函数return 0;
} 2.operator
operator有两种形式字符和字符串。
在string.h的string类里进行函数的声明。
string operator(char ch);//字符
string operator(const char* str);//字符串 在string.cpp中进行函数的实现。 前面push_back实现好了之后operator字符就可以直接复用他。
string string::operator(char ch)
{push_back(ch);return *this;
}
同样的append实现好之后operator字符串就可以直接复用他。
string string::operator(const char* str)//字符串
{append(str);return *this;
} 在test.cpp中测试一下。
void test3()
{string s1(hello world);s1 $;s1 \n;s1 hello csdn;cout s1.c_str() endl;
}
int main()
{lyj::test3(); //指定命名空间调用函数return 0;
} 3.insert
insert我们也实现两个形式插入字符和插入字符串。
在string.h的string类里进行函数的声明。
void insert(size_t pos, char ch);//插入字符
void insert(size_t pos, const char* str);//插入字符串
3.1 插入字符
在string.cpp中进行函数的实现。
假设我们现在要在2位置插入x。
执行_str[_size1]_str[_size] 。 然后--_size。 然后再执行_str[_size1]_str[_size] 。 在while循环里重复执行当_size等于pos时。 所以循环退出的条件是_sizepos。然后把_size1的字符换成插入的x。 我们再考虑特殊情况当_size为0此时_size1为1。上面的代码可行。但是我们不可以直接用_size遍历这样就直接改变_size的值我们用size来遍历。代码如下。
void string::insert(size_t pos, char ch)//插入字符
{assert(pos 0 pos _size);int size _size; //用size遍历不用_sizeif (_size _capacity)//空间不够开空间{string::reserve(_capacity 0 ? 4 : _capacity * 2);}while (size pos){_str[size 1] _str[size];--size;}_str[size 1] ch;_size;
}
但是我们会发现当size0时代码运行崩溃了。因为C语言里两个数比较的时候会自动发生类型提升。所以这里的int类型的size被提升成了和pos一样的类型导致代码死循环。所以这里要做一个类型转换。
void string::insert(size_t pos, char ch)//插入字符
{assert(pos 0 pos _size);int size _size; //用size遍历不用_sizeif (_size _capacity)//空间不够开空间{string::reserve(_capacity 0 ? 4 : _capacity * 2);}while (size (int)pos) //类型转换{_str[size 1] _str[size];--size;}_str[size 1] ch;_size;
} 在test.cpp中测试一下。
void test4()
{string s;string s1(hello world);s1.insert(0, x);cout s1.c_str() endl;
}
int main()
{lyj::test4(); //指定命名空间调用函数return 0;
} 3.2 插入字符串
在string.cpp中进行函数的实现。
假设我们现在要在3位置插入8个x。 我们要在位置3往后留出len个长度。 让_str[sizelen]_str[size]。 然后size--; sizelen也就前移了。 再执行 _str[sizelen]_str[size]; 一直循环到size等于pos。 执行 _str[sizelen]_str[size]; 然后size--; 此时数据的移动就完成了。我们把8个x插进去。_strpos位置开始插插len个。
void string::insert(size_t pos, const char* str)//插入字符串
{assert(pos 0 pos _size);size_t len strlen(str);//提前计算str的长度int size _size; //用size遍历不用_sizeif (_size len _capacity)//空间不够开空间{//如果str太长不按2倍扩reserve(_size len _capacity * 2 ? _size len : _capacity * 2);}while (size (int)pos)//要类型转换{_str[size len] _str[size];--size;}//把str插进去起始位置是_strpos//这里不用strcpy,因为strcpy会把\0也拷贝过去。memcpy(_str pos, str, len);//用memcpy_size len;//更新_size的值
}
这里不用strcpy,因为strcpy会把\0也拷贝过去我们选择用memcpy拷贝len个字节就是str的内容大小。 在test.cpp中测试一下。
void test4()
{string s;string s1(hello world);s1.insert(3, xxxxxxxx);cout s1.c_str() endl;
} 头插、尾插、中间插入都是没问题的 。 4.erase
把pos位置开始的len个字符删了。删除数据的时候参数列表第二个参数要给一个缺省值npos这个npos要自己定义在string类里。
private:char* _str;size_t _size;size_t _capacity;static const size_t npos -1;//这里可以直接初始化只有整形可以 在string.h的string类里进行函数的声明。
void erase(size_t pos, size_t len npos);//删除 在string.cpp中进行函数的实现。
分两种情况讨论。
1len比pos后面的剩余的字符数大。 所以我们只需要把pos位置改为\0。此时_sizepos.
2 len比pos后面的剩余的字符数小。 这样就可以了第一个\0后面的东西根本不用管。此时_size大小为_size-len。
void string::erase(size_t pos, size_t len)//删除
{assert(_size 0);//删除数据前提是有数据assert(pos 0 pos _size);if (len _size - pos)//情况1{_str[pos] \0;_size pos;}else //情况2{while (pos len _size){_str[pos] _str[pos len];pos;}_size - len;}
} 在test.cpp中测试一下。
void test5()
{string s;string s1(hello world);s1.erase(0, 1);//头删cout s1.c_str() endl;s1.erase(5, 3);//中间删cout s1.c_str() endl;s1.erase(3);//不传第二个参数cout s1.c_str() endl;
} 结果没问题。 string类的模拟实现就说这么多。模拟实现目的是帮助我们更好的理解string。
本篇就到这里拜拜~