一、string类方法使用举例
1.迭代器
迭代器本质:指针(理解)
迭代器:正向迭代器: begin() | end() 反向迭代器: rbegin() | rend()
2.find使用
//找到s中某个字符
void TestString3()
{
string s("AAADEFNUIENFUIAAA");
//找到AAA位置
size_t pos = s.find("AAA");
cout << pos << endl;
}
输出0,表示0位置处为AAA
3.获取文件后缀/substr
substr(pos = 0, n = npos);
从Pos位置开始,截取n个字符,如果n没有传递,表示从pos一直截取到末尾
如果都没有传递,截取整个字符
void TestString3()
{
string s("124.text.cpp");
//rfind从后面往前找 ’.’,+1找到后缀位置
size_t pos =s.rfind('.') + 1;
//从pos处截到末尾
string postfix = s.substr(pos);
cout << postfix << endl;
}
4.给多行单词,获取每行单词中最后一个单词的长度/getline
int main()
{
string line;
// 不要使用cin>>line,因为会它遇到空格就结束了
// while(cin>>line)
while (getline(cin, line))
{
size_t pos = line.rfind(' ');
cout << line.size() - pos - 1 << endl;
}
return 0;
}
getline(cin,s): 获取一整行字符串,字符串中如果包含空格等空白字符也可以接收
oj练习
5.比大小
void Test()
{
string s1("abc");
string s2("afwef");
if (s1 < s2)
{
cout << "s1<s2" << endl;
}
else if (s1>s2)
{
cout << "s1>s2" << endl;
}
else
{
cout << "s1=s2" << endl;
}
}
6.其他一些练习OJ
反转字母OJ
找第一个出现的相同的字符
验证回文串
二. string类的模拟实现
1. 浅拷贝
浅拷贝:也称位拷贝,编译器只是将对象中的值拷贝过来。如果对象中管理资源,最后就会导致多个对象共享同一份资源,当一个对象销毁时就会将该资源释放掉,而此时另一些对象不知道该资源已经被释放,以为还有效,所以当继续对资源进项操作时,就会发生发生了访问违规
上述String类没有显式定义其拷贝构造函数与赋值运算符重载,此时编译器会合成默认的,当用s1构造s2时,编译器会调用默认的拷贝构造。最终导致的问题是,s1、s2共用同一块内存空间,在释放时同一块空间被释放多次而引起程序崩溃,这种拷贝方式,称为浅拷贝
2、解决浅拷贝的方法:深拷贝,写时拷贝(了解)
如果一个类中涉及到资源的管理,其拷贝构造函数、赋值运算符重载以及析构函数必须要显式给出。一般情况都是按照深拷贝方式提供
3.String类的模拟实现
正确实现String
深拷贝,传统版本
class String
{
public:
String(const char* str = "")
{
if (nullptr == str)
str == "";
_str = new char[strlen(str) + 1];
strcpy(_str, str);
}
String(const String& s)
:_str(new char[strlen(s._str) + 1])
{
strcpy(_str, s._str);
}
String& operator=(const String& s)
{
if (this != &s)
{
char* pStr = new char[strlen(s._str) + 1];
strcpy(pStr, s._str);
delete[] _str;
_str = pStr;
}
return *this;
}
~String()
{
if (_str)
{
delete[]_str;
_str = nullptr;
}
}
private:
char* _str;
};
void TestString()
{
String s1("hello");
String s2(s1);
String s3(s2);
}
int main()
{
TestString();
return 0;
}
如下,每个对象都有自己独立的空间,释放时也是,只释放自己的互不影响
深拷贝(现代版写法)
减少传统代码重复,相似性代码进行优化
class String
{
public:
String(const char* str = "")
{
if (nullptr == str)
{
assert(false);
return;
}
_str = new char[strlen(str) + 1];
strcpy(_str, str);
}
String(const String& s)
: _str(nullptr)//_Str可能为随机指针,要先置为空
{
String strTmp(s._str);
swap(_str, strTmp._str);//交换地址
}
String& operator=(String s)//赋值运算符重载,先传入参数
{
swap(_str, s._str);//
return *this;
}
4.写时拷贝
写时拷贝就是一种拖延症,是在浅拷贝的基础之上增加了引用计数的方式来实现的。
引用计数:用来记录资源使用者的个数。在构造时,将资源的计数给成1,每增加一个对象使用该资源,就给计数增加1,当某个对象被销毁时,先给该计数减1,然后再检查是否需要释放资源,如果计数为1,说明该对象时资源的最后一个使用者,将该资源释放;否则就不能释放,因为还有其他对象在使用该资源
三、string模拟实现代码(全部)
#include <assert.h>
#include<iostream>
#include<string>
using namespace std;
namespace zx
{
class string
{
public:
typedef char* iterator;
///
// 构造
string(const char* str = "")
{
if (nullptr == str)
str = "";
_size = strlen(str);
_capacity = _size;
_str = new char[_capacity + 1];
strcpy(_str, str);
}
string(const string& s)
{
string temp(s._str);
this->swap(temp);
}
string(size_t n, char val)
{
_str = new char[n + 1];
memset(_str, val, n);
_str[n] = '\0';
_size = n;
_capacity = n;
}
string& operator=(string s)
{
this->swap(s);
return *this;
}
~string()
{
if (_str)
{
delete[] _str;
_str = nullptr;
_capacity = 0;
_size = 0;
}
}
/
// 迭代器
iterator begin()
{
return _str;
}
iterator end()
{
return _str + _size;
}
/
// 容量
size_t size()const
{
return _size;
}
size_t length()const
{
return _size;
}
size_t capacity()const
{
return _capacity;
}
bool empty()const
{
return 0 == _size;
}
void clear()
{
_size = 0;
}
void resize(size_t newsize, char val)
{
size_t oldsize = size();
if (newsize > oldsize)
{
// 有效元素个数增多
if (newsize > capacity())
reserve(newsize);
// 多出的元素使用val填充
memset(_str + _size, val, newsize - _size);
}
_size = newsize;
_str[_size] = '\0';
}
void resize(size_t newsize)
{
resize(newsize, '\0');
}
void reserve(size_t newcapacity)
{
size_t oldcapacity = capacity();
if (newcapacity > oldcapacity)
{
// 1. 申请新空间
char* temp = new char[newcapacity + 1];
// 2. 拷贝元素
strncpy(temp, _str, _size);
// 3. 释放旧空间
delete[] _str;
// 4. 使用新空间
_str = temp;
_capacity = newcapacity;
_str[_size] = '\0';
}
}
// 元素访问
char& operator[](size_t index)
{
assert(index < _size);
return _str[index];
}
const char& operator[](size_t index)const
{
assert(index < _size);
return _str[index];
}
char& at(size_t index)
{
// 如果越界,抛出out_of_range的异常
return _str[index];
}
const char& at(size_t index)const
{
// 如果越界,抛出out_of_range的异常
return _str[index];
}
//
// modify
void push_back(char ch)
{
*this += ch;
}
string& operator+=(char ch)
{
if (_size == _capacity)
reserve((size_t)_capacity*1.5 + 3);
_str[_size] = ch;
++_size;
_str[_size] = '\0';
return *this;
}
string& operator+=(const char* str)
{
size_t needSpace = strlen(str);
size_t leftSpace = capacity() - size();
if (needSpace > leftSpace)
{
reserve(capacity()+ needSpace);
}
strcat(_str, str);
_size += needSpace;
_str[_size] = '\0';
return *this;
}
string& operator+=(const string& s)
{
*this += s.c_str();
return *this;
}
string& append(const char* str)
{
*this += str;
return *this;
}
string& appent(const string& s)
{
*this += s;
return *this;
}
string& insert(size_t pos, const string& s);
string& erase(size_t pos = 0, size_t n = npos);
void swap(string& s)
{
std::swap(_str, s._str);
std::swap(_size, s._size);
std::swap(_capacity, s._capacity);
}
const char* c_str()const
{
return _str;
}
size_t find(char ch, size_t pos = 0)const
{
if (pos >= _size)
{
return npos;
}
for (size_t i = pos; i < _size; ++i)
{
if (_str[i] == ch)
return i;
}
return npos;
}
size_t rfind(char c, size_t pos = npos)
{
if (pos >= _size)
{
pos = _size-1;
}
for (int i = pos; i >= 0; --i)
{
if (_str[i] == c)
return i;
}
return npos;
}
string substr(size_t pos = 0, size_t n = npos) const
{
// 从pos位置开始,往后借助n个字符长度
if (pos >= _size)
{
return string();
}
// 从pos到字符串的末尾剩余字符个数
n = min(n, _size - pos);
string temp(n, '\0');
size_t index = 0;
for (size_t i = pos; i < pos+n; ++i)
{
temp[index++] = _str[i];
}
return temp;
}
private:
char* _str;
size_t _size;
size_t _capacity;
const static size_t npos = -1;
friend ostream& operator<<(ostream& out, const string& s);
};
ostream& operator<<(ostream& out, const string& s)
{
for (size_t i = 0; i < s.size(); ++i)
{
cout << s[i];
}
return out;
}
}
int main()
{
// TestMyString01();
// TestMyString02();
// TestMyString03();
TestMyString04();
_CrtDumpMemoryLeaks();
return 0;
}