前面两篇博客我们介绍了string类接口以及实现~std::string
是C++标准库中的字符串类,提供丰富的成员函数用于字符串操作,如构造、访问、修改、比较、查找子串等。它支持通过索引访问字符,迭代器遍历,以及高效的内存管理,是C++中处理字符串的首选工具~
#pragma once
#include<iostream>
#include<string.h>
#include<assert.h>
using namespace std;
namespace Xiaodu
{
class my_string//与库里面的进行区分
{
private:
char* _str;//字符指针
size_t _size;//统计长度
size_t _capacity;//统计最大容量
const static size_t _npos;//静态常量,用于表示一个无效的位置或未找到的位置
public:
//成员函数
//构造
my_string(const char* str);
my_string(size_t n, char ch);
//析构
~my_string();
//默认构造
my_string();
void clear()
{
_str[0] = '\0';
_size = _capacity = 0;
}
//友元声明
//<<运算符重载
friend ostream& operator<<(ostream& out, my_string& s);
//>>运算符重载
friend istream& operator>>(istream& in, my_string& s);
//拷贝构造
my_string(const my_string& s);
//赋值运算符重载
my_string& operator=(my_string& s);
//reserve
void reserve(size_t n);
//push_back
void push_back(char ch);
//append
void append(const char* s);
//+=一个字符
my_string& operator+=(char c);
//+=一个字符串
my_string& operator+=(const char* c);
//insert字符
void insert(size_t pos, size_t n, char c);
//insert字符串
void insert(size_t pos, const char* s);
//erase
void erase(size_t pos, size_t n);
//find字符
size_t find(char c, size_t pos = 0);//声明给默认参数!!!
//find字符串
size_t find(const char* s, size_t pos = 0);
//substr
my_string substr(size_t pos = 0, size_t len = _npos);
//==
bool operator==(const my_string& s)const;
//!=
bool operator!=(const my_string& s)const;
//<
bool operator<(const my_string& s)const;
//<=
bool operator<=(const my_string& s)const;
//>
bool operator>(const my_string& s)const;
//>=
bool operator>=(const my_string& s)const;
};
//<<运算符重载
ostream& operator<<(ostream& out, my_string& s);
//>>运算符重载
istream& operator>>(istream& in, my_string& s);
//getline
istream& getline(istream& in, my_string& s, char end = '\n');//可以自己指定获取字符串结束的标志
}
#include"string.h"//记得包含头文件
namespace Xiaodu
{
const size_t my_string::_npos = -1;
//构造
my_string::my_string(const char* str)//常量字符串
:_size(strlen(str))//使用strlen求有效长度来初始化
{
//使用已经初始化的_size来初始化剩下的
_capacity = _size;
_str = new char[_size + 1];
strcpy(_str, str);
}
my_string::my_string(size_t n, char ch)
:_size(n),_str(new char[n+1]),_capacity(n)
{
for (size_t i = 0; i < n; i++)
{
_str[i] = ch;
}
_str[_size] = '\0';//结束标志\0
}
//默认构造
my_string::my_string()
{
_str = new char[1];
_str[0] = '\0';//一个字符保存'\0'
_size = 0;
_capacity = 0;
}
//析构
my_string::~my_string()
{
delete _str;//new,delete匹配使用
_str = nullptr;
_size = 0;
_capacity = 0;
}
//拷贝构造
//s2(s1)
//传统写法
/*my_string::my_string(const my_string& s)
{
_size = s._size;
_capacity = s._capacity;
_str = new char[_capacity + 1];
strcpy(_str, s._str);
}*/
//现代写法
my_string::my_string(const my_string& s)
{
my_string tmp(s._str);//让构造帮我们写
swap(_str, tmp._str);
swap(_size, tmp._size);
swap(_capacity, tmp._capacity);
}
//赋值运算符重载
//my_string::operator=——这样指定类域
//s4=s3
my_string& my_string::operator=(my_string& s)
{
//判断是不是自己给自己赋值
if (this != &s)
{
delete _str;//释放原来的,重新开辟空间
_str = new char[s._capacity + 1];
strcpy(_str, s._str);
_size = s._size;
_capacity = s._capacity;
}
return *this;
}
void my_string::reserve(size_t n)
{
if (n > _capacity)//修改容量比原来的大就进行扩容
{
char* tmp = new char[n + 1];
//创建一个中间指针变量修改容量
strcpy(tmp, _str);
delete _str;
_str = tmp;
_capacity = n;
}
}
void my_string::push_back(char ch)
{
//判断容量是否足够
if (_capacity == _size)//容量不够进行扩容
{
//这里就可以使用reserve进行代码复用
reserve(_capacity == 0 ? 4 : _capacity * 2);
}
_str[_size++]=ch;//插入字符后长度增加
_str[_size] = '\0';
}
void my_string::append(const char* s)
{
//求出插入字符串长度
size_t l = strlen(s);
//容量不够进行扩容
if (_size + l > _capacity)
{
//默认两倍扩容,还是不够就按需扩容
size_t newcapacity = _capacity * 2;
if (_size + l > newcapacity)
{
newcapacity = _size + l;
}
//1.自己重新写
char* tmp = new char[newcapacity + 1];//容量记得+1,需要一个字符串结束标志
strcpy(tmp, _str);
delete _str;
_str = tmp;
_capacity = _size + l;
//代码复用
//reserve(newcapacity);
}
//拷贝剩下的
strcpy(_str + _size, s);
//_size增加
_size += l;
}
//+=一个字符
my_string& my_string::operator+=(char c)
{
push_back(c);
return *this;
}
//返回引用,减少拷贝
//+=一个字符串
my_string& my_string::operator+=(const char* c)
{
append(c);
return *this;
}
//insert字符
void my_string::insert(size_t pos, size_t n, char c)
{
//判断插入位置和插入个数是否合法
assert(pos < _size);
assert(n > 0);
//判断容量是否足够
//不够进行扩容
if (_size + n > _capacity)
{
//默认两倍扩容,还是不够就按需扩容
size_t newcapacity = _capacity * 2;
if (_size + n > newcapacity)
{
newcapacity = _size + n;
}
//代码复用
reserve(newcapacity);
}
//移动后面的字符
size_t end = _size + n - 1;
//从后面开始移动,避免覆盖
while (end > pos + n - 1)
{
_str[end] = _str[end - n];
end--;
}
//插入字符
for (size_t i = pos; i < pos + n; i++)
{
_str[i] = c;
}
_size += n;
//字符串末尾置为'\0'
_str[_size] = '\0';
}
//insert字符串
//void my_string::insert(size_t pos, const char* s)
//{
// //方法一:重新写
// //判断插入位置和插入个数是否合法
// size_t n = strlen(s);
// assert(pos < _size);
// assert(n);
// //判断容量是否足够
// //不够进行扩容
// if (_size + n > _capacity)
// {
// //默认两倍扩容,还是不够就按需扩容
// size_t newcapacity = _capacity * 2;
// if (_size + n > newcapacity)
// {
// newcapacity = _size + n;
// }
// //代码复用
// reserve(newcapacity);
// }
// //移动后面的字符
// size_t end = _size + n - 1;
// //从后面开始移动,避免覆盖
// while (end > pos + n - 1)
// {
// _str[end] = _str[end - n];
// end--;
// }
// //插入字符串里面的字符
// for (size_t i = pos; i < pos + n; i++)
// {
// _str[i] = s[i - pos];
// }
// _size += n;
// //字符串末尾置为'\0'
// _str[_size] = '\0';
//}
void my_string::insert(size_t pos, const char* s)
{
//方法二:代码复用
size_t n = strlen(s);
//先占位置,再重新赋值
insert(pos, n, 'x');
for (size_t i = 0; i < n; i++)
{
_str[pos + i] = s[i];
}
}
//erase
void my_string::erase(size_t pos, size_t n)
{
//判断删除位置
if (pos + n >= _size)
//也就是后面的全部删除
{
_str[pos] = '\0';
_size -= n;
}
else
//删除直接进行覆盖就好了
{
//把后面的字符向前面移动
size_t begin = pos + n;
while (begin < _size)
{
_str[begin - n] = _str[begin];
begin++;
}
_size -= n;
_str[_size] = '\0';
}
}
//find字符
size_t my_string::find(char c,size_t pos)
//默认从开头开始找
{
//遍历查找
size_t n = strlen(_str);
for (size_t i = pos; i < n; i++)
{
if (_str[i] == c)
{
//找到了返回下标
return i;
}
}
//找不到返回_npos
return _npos;
}
//find字符串
size_t my_string::find(const char* s, size_t pos)
{
const char* p = strstr(_str + pos, s);//从指定位置开始查找子字符串
if (p == nullptr)//没有找到,返回_npos
{
return _npos;
}
else//找到了,返回下标索引
{
return p - _str;
}
}
//substr
my_string my_string::substr(size_t pos, size_t len)
{
size_t n = strlen(_str);
assert(pos >= 0);
assert(pos < n);//判断拷贝位置有效
my_string tmp;//调用默认构造
tmp._str = new char[len + 1];
//进行拷贝
for (size_t i = pos; i < pos + len; i++)
{
tmp._str[i - pos] = _str[i];
}
tmp._str[len] = '\0';
tmp._size = tmp._capacity = len;//修改容量和长度
return tmp;
}
//==
//s1==s2
bool my_string::operator==(const my_string& s)const
{
return strcmp(_str, s._str) == 0;//判断返回值是否等于0
}
//!=
bool my_string::operator!=(const my_string& s)const
{
return !(*this == s);//代码复用
}
//<
bool my_string::operator<(const my_string& s)const
{
return strcmp(_str, s._str) < 0;
}
//<=
bool my_string::operator<=(const my_string& s)const
{
return (*this == s) || (*this < s);
}
//>
bool my_string::operator>(const my_string& s)const
{
return !(*this <= s);
}
//>=
bool my_string::operator>=(const my_string& s)const
{
return !(*this < s);
}
/*ostream& operator<<(ostream& out, my_string& s)
{
out << "_str:" << s._str << endl;
out << "_size:" << s._size << endl;
out << "_capacity:" << s._capacity << endl;
return out;
}*/
ostream& operator<<(ostream& out, my_string& s)
{
cout << s._str;
return out;
}
>>运算符重载
//istream& operator>>(istream& in, my_string& s)
//{
// char ch;
// in >> ch;//err in忽略空格和换行符
// while (ch != ' ' && ch != '\n')
// {
// s += ch;
// in >> ch;
// }
// return in;
//}
>>运算符重载
//istream& operator>>(istream& in, my_string& s)
//{
// //清理原来的字符串
// s.clear();
// char ch = in.get();//调用get
// while (ch != ' ' && ch != '\n')
// {
// s += ch;
// ch = in.get();
// }
// return in;
//}
//>>运算符重载(优化版)
istream& operator>>(istream& in, my_string& s)
{
//清理原来的字符串
s.clear();
const size_t N = 1024;
char arr[N];//使用一个临时数组(出了当前作用域就销毁)来存储写入的字符数据
int i = 0;
char ch = in.get();//调用get
while (ch != ' ' && ch != '\n')
{
arr[i++] = ch;
if (i == N - 1)
{
arr[i] = '\0';
s += arr;//字符串很长的情况下,调用+=可以按需扩容
i = 0;//i重新开始保存数据
}
ch = in.get();
}
if (i > 0)//arr里面还有字符数据
{
arr[i] = '\0';//末尾置为'\0'再进行插入
s += arr;
}
return in;
}
//getline
istream& getline(istream& in, my_string& s, char end)
{
//清理原来的字符串
s.clear();
const size_t N = 1024;
char arr[N];//使用一个临时数组(出了当前作用域就销毁)来存储写入的字符数据
int i = 0;
char ch = in.get();//调用get
while (ch != end)
{
arr[i++] = ch;
if (i == N - 1)
{
arr[i] = '\0';
s += arr;//字符串很长的情况下,调用+=可以按需扩容
i = 0;//i重新开始保存数据
}
ch = in.get();
}
if (i > 0)//arr里面还有字符数据
{
arr[i] = '\0';//末尾置为'\0'再进行插入
s += arr;
}
return in;
}
}
#include"string.h"
namespace Xiaodu
{
void test1()
{
my_string s1("Hello!!!");
my_string s2;
my_string s3(6, '6');
cout << s1 << endl;
cout << s2 << endl;
cout << s3 << endl;
}
void test2()
{
my_string s1("Hello!");
my_string s2(s1);//拷贝构造
cout << s1 << endl;
cout << s2 << endl;
my_string s3("Xiaodu!");
my_string s4("Haha!");
s4 = s3 = s1;//连续赋值
cout << s3 << endl;
cout << s4 << endl;
}
void test3()
{
my_string s1("Hello!");
s1.reserve(5);
cout << s1 << endl;
s1.reserve(10);
cout << s1 << endl;
}
void test4()
{
my_string s1("HH");
cout << s1 << endl;
s1.push_back('X');
s1.push_back('X');
s1.push_back('X');
s1.push_back('X');
s1.push_back('X');
s1.push_back('X');
s1.push_back('X');
cout << s1 << endl;
}
void test5()
{
my_string s1("Hello!");
cout << s1 << endl;
s1.append(" Xiaodu!");
cout << s1 << endl;
s1 += 'h';
cout << s1 << endl;
s1 += "HHH";
cout << s1 << endl;
}
void test6()
{
my_string s1 = "XXXXXX";
cout << s1 << endl;
s1.insert(2, 8, 'H');
cout << s1 << endl;
s1.insert(4,"DDD");
cout << s1 << endl;
s1.erase(4, 6);
cout << s1 << endl;
s1.erase(6, 5);
cout << s1 << endl;
}
void test7()
{
my_string s1("Hello!");
if (s1.find('l', 2) != -1)//判断是不是等于npos
{
cout << "找到了,下标是" << s1.find('l', 2) << endl;
}
else
{
cout << "没有找到" << endl;;
}
if (s1.find('X') != -1)
{
cout << "找到了,下标是" << s1.find('X') << endl;
}
else
{
cout << "没有找到" << endl;;
}
}
void test8()
{
my_string s1("Hello,World! Hello,Xiaodu!");
size_t ret1 = s1.find("Hello");
if (ret1 != -1)
{
cout << "找到了,下标是" << ret1 << endl;
}
else
{
cout << "没有找到" << endl;;
}
size_t ret2 = s1.find("Hello", 8);
if (ret2 != -1)
{
cout << "找到了,下标是" << ret2 << endl;
}
else
{
cout << "没有找到" << endl;;
}
size_t ret3 = s1.find("XXX");
if (ret3 != -1)
{
cout << "找到了,下标是" << ret3 << endl;
}
else
{
cout << "没有找到" << endl;;
}
}
void test9()
{
my_string s1 = "Hello,Xiaodu!";
my_string r1 = s1.substr(0, 5);
cout << s1 << endl;
cout << r1 << endl;
}
void test10()
{
string s1("Hello!");
string s2("Hello!");
string s3("Hello! Xiaodu");
if (s1 == s2)
{
cout << "s1 == s2" << endl;
}
else
{
cout << "s1!=s2" << endl;
}
if (s1 == s3)
{
cout << "s1 == s3" << endl;
}
else
{
cout << "s1!=s3" << endl;
}
if (s1 <= s3)
{
cout << "s1 <= s3" << endl;
}
if (s3 >= s1)
{
cout << "s3 >= s1" << endl;
}
}
void test11()
{
my_string s1("Hello!");
my_string s2("Xiaodu!");
cout << s1 << s2 << endl;
cin >> s1 >> s2;
cout << s1 << s2 << endl;
my_string s3;
cin >> s3;
cout << s3 << endl;
}
void test12()
{
my_string s1("Haha!");
my_string s2;
my_string s3;
cout << s1 << endl;
cout << s2 << endl;
getline(cin, s1);
getline(cin, s2);
cout << s1 << endl;
cout << s2 << endl;
getline(cin, s3, '!');//也可以自己指定一行结束符号
cout << s3 << endl;
}
}
int main()
{
//Xiaodu::test1();
Xiaodu::test2();
//Xiaodu::test3();
//Xiaodu::test4();
//Xiaodu::test5();
//Xiaodu::test6();
//Xiaodu::test7();
//Xiaodu::test8();
//Xiaodu::test9();
//Xiaodu::test10();
//Xiaodu::test11();
Xiaodu::test12();
return 0;
}