- 本期主题:string类的模拟实现
- 博客主页:小峰同学
- 分享小编的在Linux中学习到的知识和遇到的问题
小编的能力有限,出现错误希望大家不吝赐
身为程序员,不会还有人没有女朋友吧。
直接上源码
#pragma once
#include<iostream>
#include<string>
#include<assert.h>
#include<string.h>
using namespace std;
namespace zxf
{
class string
{
public:
typedef char* iterator;
typedef const char* const_iterator;
public:
/成员函数///
//构造函数
//string(const char* str = "\0")
//string(const char* str = nullptr)
//string(const char* str = NULL)
//以上都是错误示范。
string(const char* str = "")
{
//如果这里str位nullptr就是程序非法的
if (nullptr == str)
{
assert(str);
exit(1);
}
_size = strlen(str);
_capacity = _size;
_str = new char[_capacity + 1];//这里自己控制是否加一,根据capacity的具体意义确定。
strcpy(_str, str);
}
//拷贝构造(古老写法)
//string(const string& s)
//{
// _size = s._size;
// _capacity = s._capacity;
// _str = new char[_capacity+1];
// //注意这里的+1,没有的话可能会报错。
// strcpy(_str, s._str);
//}
//拷贝构造(现代写法)
string(const string& s)
:_str(nullptr)
,_size(0)
,_capacity(0)
{//注意这里的初始化列表不能少,不写后面tmp在析构的时候就会出问题。
string tmp(s._str);
//swap(tmp);
this->swap(tmp);
//是否加this指针都是在使用 自己的成员函数swap
}
//赋值重载(传统写法)
//string& operator=(const string& s)
//{
// if (this != &s)//这里用地址比较,不能用对象比较因为我们还没重载 == 号
// {
// char* pStr = new char[strlen(s._str) + 1];
// strcpy(pStr, s._str);
// delete[] _str;//要释放掉原来的空间。
// _str = pStr;
// _size = s._size;
// _capacity = s._capacity;
// }
// return *this;
// //if (this != &s)
// //{
// // string tmp(s);
// // swap(tmp);
// //}
// //return *this;
//}
//赋值重载(现代写法)
string& operator=(string s)
{
swap(s);
return *this;
}
//析构函数
~string()
{
if (_str)
{
delete[] _str;
_str = nullptr;
_size = 0;
_capacity = 0;
}
}
iterator
iterator begin()
{
return _str;
}
const_iterator begin()const
{
return _str;
}
iterator end()
{
return _str + _size;
}
const_iterator end()const
{
return _str + _size;
}
/get成员变量
size_t size()const
{
return _size;
}
size_t capacity()const
{
return _capacity;
}
char* c_str()const
{
return _str;
}
/其他函数
void reserve(size_t capacity)
{
if(capacity>_capacity)//一般不会缩小容量。
{
_capacity = capacity;
char* nstr = new char[_capacity + 1];
strcpy(nstr, _str);
delete[] _str;
_str = nstr;
}
}
void push_back(const char ch)
{
if (_size == _capacity)
{
//reserve(_capacity * 2);//考虑到空字符串的push_back,这里_capacity*2就会出问题。
reserve(_capacity + 10);
//也可也在这里判断一下是不是0,然后扩容
}
_str[_size++] = ch;
_str[_size] = '\0';
}
void append(const char* str)
{
size_t len = strlen(str);
if (_size + len >= _capacity)
{
reserve(_size + len * 2);
}
strcat(_str, str);
_size += len;
}
string& operator+=(const char* str)
{
append(str);
return *this;
}
string& operator+=(const char c)
{
push_back(c);
return *this;
}
void clear()
{
_size = 0;
_str[_size] = '\0';
}
bool empty()const
{
return 0 == _size;
}
//void resize(size_t newsize, char c = '\0')
//{
// if (newsize < _size)
// {
// _size = newsize;
// _str[newsize] = '\0';
// }
// if (newsize < _capacity)
// {
// for (; _size <= newsize; _size++)
// {
// _str[_size] = c;
// }
// _size--;
// }
// else
// {
// reserve(newsize);
// for (; _size <= newsize; _size++)
// {
// _str[_size] = c;
// }
// _size--;
// }
//}
//优化方案
void resize(size_t newSize, char c = '\0')
{
if (newSize > _size)
{
// 如果newSize大于底层空间大小,则需要重新开辟空间
if (newSize > _capacity)
{
reserve(newSize);
}
memset(_str + _size, c, newSize - _size);
}
_size = newSize;
_str[newSize] = '\0';
}
char& operator[](size_t pos)
{
assert(pos < _size);
return _str[pos];
}
//注意重载一个const版本。
//不然会存在一些潜在错误。
const char& operator[](size_t pos)const
{
assert(pos < _size);
return _str[pos];
}
bool operator<(const string& s)
{
return strcmp(_str, s._str) < 0;
}
bool operator<=(const string& s)
{
return strcmp(_str, s._str) <= 0;
}
bool operator>(const string& s)
{
return strcmp(_str, s._str) > 0;
}
bool operator>=(const string& s)
{
return strcmp(_str, s._str) >= 0;
}
bool operator==(const string& s)
{
return strcmp(_str, s._str) == 0;
}
bool operator!=(const string& s)
{
return !(*this == s);
}
// 返回c在string中第一次出现的位置
size_t find(char c, size_t pos = 0) const
{
assert(pos < _size);
size_t begin = pos;
while (begin < _size)
{
if (_str[begin] == c)
{
return begin;
}
begin++;
}
return npos;
}
// 返回子串s在string中第一次出现的位置
size_t find(const char* s, size_t pos = 0) const
{
assert(pos < _size);
const char* pc = strstr(_str + pos, s);//借助C语言得strstr函数实现;
if (pc == nullptr)
{
return npos;
}
else
{
return pc - _str;
}
}
// 删除pos位置上的元素,并返回该元素的下一个位置
string& erase(size_t pos, size_t len = npos)
{
assert(pos < _size);
if (len == npos || pos + len > _size)
{
_str[pos] = '\0';
_size = pos;
}
else
{
//strcpy(_str + pos, _str + pos + len);
memmove(_str + pos, _str + pos + len, _size - pos - len + 1);
//都是可以的 也可以自己控制挪动。
_size -= len;
}
return *this;
}
string& insert(size_t pos, const char c)
{
assert(pos <= _size);
if (_size == _capacity)
{
reserve(_capacity + 10);
}
//移动数据
//size_t end = _size;
//while (end >= pos)
//{
// _str[end + 1] = _str[end];
// end--;
//}//这样写pos ==0 的时候就会出问题。
size_t end = _size+1;
while (end > pos)
{
_str[end] = _str[end-1];
end--;
}//这样写也可以。
//int end = _size;
//while (end >= (int)pos)
//{
// _str[end + 1] = _str[end];
// end--;
//}//可以这样改一下
_str[pos] = c;
_size++;
_str[_size] = '\0';
return *this;
}
string& insert(size_t pos, const char* str)
{
size_t len = strlen(str);
if (_size + len >= _capacity)
{
reserve(_size + len * 2);
}
size_t end = _size;
while (end > pos)//这里也是要注意这里控制好条件和考虑好 pos ==0情况。
//这里情况很多种控制好就行。
{
_str[end + len-1] = _str[end-1];
end--;
}
strncpy(_str + pos, str, len);
_size += len;
_str[_size] = '\0';
return *this;
}
void swap(string& s)//交换函数,属于成员函数。
{
std::swap(s._str, _str);
std::swap(s._size, _size);
std::swap(s._capacity, _capacity);
}
private:
char* _str;
size_t _size;
size_t _capacity;
const static size_t npos = -1;//一般静态成员变量初始化需要再类外面初始化,
//但是有一个特例就是 const 修饰分静态成员变量,可以直接给缺省值初始化。
//但是仅仅限于整型,
};
//注意参数的引用,和返回值的引用
ostream& operator<<(ostream& out, const string& s)//<<的重载不一定非要实现成 友元函数。
{
//out << s.c_str();
//这样写是不对的,防止'\0'的出现。
for (size_t i = 0; i < s.size(); ++i)
{
out << s[i];
}
return out;
}
istream& operator>>(istream& in, string& s)
{
//一般会先清理
s.clear();
//
//char ch;
//in >> ch;
//while (ch != ' ' && ch != '\n')
//{
// s += ch;
// in >> ch;
//}
这样写会出现一个问题,istream 对象 cin 和scanf 相同 没办法取到 ' ' 和 '\n'
scanf 和 cin 只能取到非 ' ' 和 '\n' 的字符。所以这个循环位死循环。
//char ch = in.get();
//while (ch != ' ' && ch != '\n')
//{
// s += ch;
// ch = in.get();
//}
//istream类对象的成员函数 get()。
//in.get()是按照逐个字符逐个字符读取,包含 ' ' 和 '\n' 。 和cin,scanf不同。
//这样也会照成频繁扩容,对性能会有一定的影响。
//库里面是这样定义的。 //一段一段的 +=
char buff[128] = { '\0' };
size_t i = 0;
char ch = in.get();
while (ch != ' ' && ch != '\n')
{
//i 是 0 ~ 126一共存 127个字符。
if (i < 127)//这里需要留一个字符,保存'\0'
{
buff[i++] = ch;
}
else{
s += buff;
i = 0;
buff[i++] = ch;
}
ch = in.get();
}
if (i > 0){
buff[i] = '\0';
s += buff;
}
return in;
}
istream& getline(istream& in, string& s)
{
s.clear();
char buff[128] = { '\0' };
size_t i = 0;
char ch = in.get();
while (ch != '\n')//这里比 cin>> 少一个 ch != ‘ ’ 。
{
//i 是 0 ~ 126一共存 127个字符。
if (i < 127)//这里需要留一个字符,保存'\0'
{
buff[i++] = ch;
}
else {
s += buff;
i = 0;
buff[i++] = ch;
}
ch = in.get();
}
if (i > 0) {
buff[i] = '\0';
s += buff;
}
return in;
}
//这是一些测试用例。
void test1()
{
string s1("zhang");
string s2(s1);
}
void test2()
{
string s1("zhang");
string s2 = "xue";
cout << s2.c_str() << endl;
s2 = s1;
cout<< s2.c_str() << endl;
}
void test3()
{
string s1("111111");
const string s2(s1);
string::iterator first1 = s1.begin();
string::iterator last1 = s1.end();
while (first1 != last1)
{
cout << *first1;
first1++;
}
cout << endl;
string::const_iterator first2 = s2.begin();
string::const_iterator last2 = s2.end();
while (first2 != last2)
{
cout << *first2;
first2++;
}
cout << endl;
//范围for的底层就是迭代器,当我们按照底层一样的名称相同
for (auto& ch : s1)
{
ch++;
}
cout << s1.c_str() << endl;//222222
for (auto& ch : s2)
{
cout << ch << endl;
}
}
void test4()
{
string s1("zhang");
cout << s1.size() << endl;
cout << s1.capacity() << endl;
const string s2("xue");
cout << s2.size() << endl;
cout << s2.capacity() << endl;
}
void test5()
{
string s1("zhang");
string s2;
s1 += "xuefeng";
s2 += "zhangxuefeng";
cout << s1.c_str() << endl;
cout << s2.c_str() << endl;
}
void test6()
{
string s1("zhang");
s1 += 'x';
s1 += 'u';
s1 += 'e';
s1 += 'f';
s1 += 'e';
s1 += 'n';
s1 += 'g';
cout << s1.c_str() << endl;
}
void test7()
{
const string s1("zhang");
size_t size = s1.size();
//cout << size << endl;
//char& ch = s1[3];
const char& ch = s1[3];
//ch++;
cout << s1.c_str() << endl;
}
void test8()
{
string s1("zhang");
s1.insert(3, 'z');
s1.insert(3, 'z');
s1.insert(3, 'z');
s1.insert(3, 'z');
s1.insert(0, 'z');
s1.insert(0, 'z');
s1.insert(0, 'z');
s1.insert(0, 'z');
cout << s1.c_str() << endl;
string s2("zhang");
s2.insert(0, "zhang");
s2.insert(0, "xue");
s2.insert(0, "xue");
s2.insert(0, "xue");
s2.insert(0, "xue");
s2.insert(0, "xue");
s2.insert(0, "xue");
s2.insert(0, "xue");
s2.insert(0, "xue");
s2.insert(5, "xue");
s2.insert(0, "xue");
s2.insert(0, "");
s2.insert(5, "");
s2.insert(5, "");
cout << s2.c_str() << endl;
}
void test9()
{
string s1("zhang");
string s2("zhang");
string s3("zhan");
cout << (s1 == s2) << endl;//t
cout << (s1 != s2) << endl;//f
cout << (s1 == s3) << endl;//f
cout << (s1 != s3) << endl;//t
}
void test10()
{
//string s1("zhangxuefeng");
//s1.erase(0, 5);
//cout << s1.c_str() << endl;
//string s1("zhangxuefeng");
//size_t pos = s1.find("xue");
//s1.erase(pos, 3);
//size_t pos2 = s1.find('z');
//s1.erase(pos2, 1);
//cout << s1.c_str() << endl;
//string s1("zhang");
//cout << s1 << endl;
string s1("zhang");
cin >> s1;
cout << s1;
string s2("zhang");
getline(cin, s2);
cout << s2;
}
}
这里我就不一一讲解了 ,注释的很清楚。
扫描二维码关注公众号,回复:
15581786 查看本文章