目录
1.string的介绍
c语言中虽然也有字符串,但是其与对应的函数是分离的,不符合c++中面向对象的思想。而且c++中的string类使用起来更方便、快捷。
1.1简单介绍
1. string是表示字符串的字符串类2. 该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作
1.2构造函数
1.3容量操作
注意:
1. size()与length()方法底层实现原理完全相同,引入size()的原因是为了与其他容器的接口保持一致,一般情况下基本都是用size()。2. clear()只是将string中有效字符清空,不改变底层空间大小。3. resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不同的是当字符个数增多时:resize(n)用0来填充多出的元素空间,resize(size_t n, char c)用字符c来填充多出的元素空间。注意:resize在改变元素个数时,如果是将元素个数增多,可能会改变底层容量的大小,如果是将元素个数减少,底层空间总大小不变。4. reserve(size_t res_arg=0):为string预留空间,不改变有效元素个数,当reserve的参数小于string的底层空间总大小时,reserver不会改变容量大小。
1.4访问以及遍历
begin 获取一个字符的迭代器 + end 获取最后一个字符下一个位置的迭 代器
[]返回pos位置的字符,const string类对象调用
1.5修改操作
push_back在字符串后尾插字符 cappend在字符串后追加一个字符串operator+= (重点)在字符串后追加字符串 strc_str(重点)返回 C 格式字符串find + npos(重点)从字符串 pos 位置开始往后找字符 c ,返回该字符在字符串中的位置rfind从字符串 pos 位置开始往前找字符 c ,返回该字符在字符串中的位置substr在 str 中从 pos 位置开始,截取 n 个字符,然后将其返回
注意:1. 在string尾部追加字符时,s.push_back(c) / s.append(1, c) / s += 'c'三种的实现方式差不多,一般情况下string类的+=操作用的比较多,+=操作不仅可以连接单个字符,还可以连接字符串。2. 对string操作时,如果能够大概预估到放多少字符,可以先通过reserve把空间预留
1.6非成员函数
2.模拟实现
在模拟实现string类时尤其要考虑深浅拷贝问题,若没显示写使用编译器默认生成的,则是浅拷贝
说明:上述String类没有显式定义其拷贝构造函数与赋值运算符重载,此时编译器会合成默认的,当用s1构造s2时,编译器会调用默认的拷贝构造。最终导致的问题是,s1、s2共用同一块内存空间,在释放时同一块空间被释放多次而引起程序崩溃,这种拷贝方式,称为浅拷贝。
2.1深浅拷贝概念
浅拷贝:也称位拷贝,编译器只是将对象中的值拷贝过来。如果对象中管理资源,最后就会导致多个对象共享同一份资源,当一个对象销毁时就会将该资源释放掉,而此时另一些对象不知道该资源已经被释放,以为还有效,所以当继续对资源进项操作时,就会发生发生了访问违规。
深拷贝:如果一个类中涉及到资源的管理,其拷贝构造函数、赋值运算符重载以及析构函数必须显式给出。一般情况都是按照深拷贝方式提供。
显式深拷贝的写法

2.2写时拷贝
写时拷贝就是一种拖延症,是在浅拷贝的基础之上增加了引用计数的方式来实现的。引用计数:用来记录资源使用者的个数。在构造时,将资源的计数给成1,每增加一个对象使用该资源,就给计数增加1,当某个对象被销毁时,先给该计数减1,然后再检查是否需要释放资源,如果计数为1,说明该对象时资源的最后一个使用者,将该资源释放;否则就不能释放,因为还有其他对象在使该资源。
2.3代码实现(包含测试用例)
.h
#pragma once
#include<iostream>
#include<assert.h>
using namespace std;
namespace bit {
class string {
public:
typedef char* iterator;
typedef const char* const_iterator;
iterator begin();
iterator end();
const_iterator begin() const;
const_iterator end() const;
string(const char* str="");
string(const string& str);
string& operator=(string str);
~string();
const char* c_str() const;
size_t size() const;
char& operator[](size_t pos);
const char& operator[](size_t pos) const;
void reserve(size_t n);
void pushback(char ch);
void append(const char* str);
string& operator+=(char ch);
string& operator+=(const char* str);
void insert(size_t pos, char ch);
void insert(size_t pos, const char* str);
void erase(size_t pos = 0, size_t len=npos);
size_t find(char ch, size_t pos = 0);
size_t find(const char* str, size_t pos = 0);
void swap(string& str);
bool operator<(const string& str) const;
bool operator>(const string& str) const;
bool operator<=(const string& str) const;
bool operator>=(const string& str) const;
bool operator==(const string& str) const;
bool operator!=(const string& str) const;
void clear();
private:
char* _str=nullptr;
size_t _size = 0;
size_t _capacity = 0;
const static size_t npos;
};
ostream& operator<<(ostream& os,const string& str);
istream& operator>>(istream& os,string& str);
}
.cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include"string.h"
namespace bit{
const size_t string::npos = -1;
string::string(const char* str)
:_size(strlen(str))
{
_str = new char[_size + 1];
_capacity = _size;
strcpy(_str, str);
}
string::string(const string& str) {
string tmp(str.c_str());
swap(tmp);
}
string& string::operator=(string str) {
swap(str);
return *this;
}
string::~string() {
delete[] _str;
_str = nullptr;
_size = _capacity = 0;
}
const char* string::c_str() const {
return _str;
}
size_t string::size() const{
return _size;
}
char& string::operator[](size_t pos) {
assert(pos < _size);
return _str[pos];
}
const char& string::operator[](size_t pos) const {
assert(pos < _size);
return _str[pos];
}
string::iterator string::begin() {
return _str;
}
string::iterator string::end() {
return _str + _size;
}
string::const_iterator string::begin() const {
return _str;
}
string::const_iterator string::end() const {
return _str + _size;
}
void string::reserve(size_t n) {
if (n > _capacity) {
char* tmp = new char [n + 1];
strcpy(tmp, _str);
delete[] _str;
_str = tmp;
_capacity = n;
}
}
void string::pushback(char ch) {
insert(_size,ch);
}
void string::append(const char* str) {
insert(_size,str);
}
string& string::operator+=(char ch) {
pushback(ch);
return *this;
}
string& string::operator+=(const char* str) {
append(str);
return *this;
}
void string::insert(size_t pos, char ch) {
assert(pos <= _size);
if (_size == _capacity) {
size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2;
reserve(newcapacity);
}
size_t end = _size + 1;
while (end > pos) {
_str[end] = _str[end - 1];
end--;
}
_str[pos] = ch;
_size++;
}
void string::insert(size_t pos, const char* str) {
assert(pos <= _size);
size_t len = strlen(str);
if (_size + len > _capacity) {
reserve(_size + len);
}
size_t end = _size + len;
while (end>pos+len-1) {
_str[end] = _str[end - len];
end--;
}
memcpy(_str + pos, str, len);
_size += len;
}
void string::erase(size_t pos, size_t len) {
assert(pos <= _size);
if (len >= _size - pos) {
_str[pos] = '\0';
_size = pos;
}
else {
strcpy(_str + pos, _str + pos + len);
_size -= len;
}
}
size_t string::find(char ch, size_t pos) {
assert(pos <= _size);
for (int i = 0; i < _size; i++) {
if (_str[i] == ch) {
return i;
}
}
return npos;
}
size_t string::find(const char* str, size_t pos) {
assert(pos <= _size);
char* p = strstr(_str,str);
return p - _str;
}
void string::swap(string& str) {
std::swap(_str,str._str);
std::swap(_size,str._size);
std::swap(_capacity,str._capacity);
}
bool string::operator<(const string& str) const {
return std::strcmp(_str, str._str) < 0;
}
bool string::operator>(const string& str) const {
return !(*this <= str);
}
bool string::operator<=(const string& str) const {
return *this < str || *this == str;
}
bool string::operator>=(const string& str) const {
return !(*this < str);
}
bool string::operator==(const string& str) const {
return std::strcmp(_str, str._str) == 0;
}
bool string::operator!=(const string& str) const {
return !(*this==str);
}
void string::clear() {
_str[0] = '\0';
_size = 0;
}
ostream& operator<<(ostream& os, const string& str) {
for (int i = 0; i < str.size(); i++) {
os << str[i];
}
return os;
}
istream& operator>>(istream& is, string& str) {
str.clear();
char buff[128];
int i = 0;
char ch=is.get();
while (ch != '\n' && ch != ' ') {
buff[i++]= ch;
if (i == 127) {
buff[i] = '\0';
str += buff;
i = 0;
}
ch = is.get();
}
buff[i] = '\0';
str += buff;
return is;
}
}
test
#define _CRT_SECURE_NO_WARNINGS 1
#include"string.h"
namespace bit{
void test_string1() {
string s;
cout << s.c_str() << endl;
string ss("hello world");
cout << ss.c_str() << endl;
for (int i = 0; i < ss.size(); i++) {
cout << ss[i] << " ";
}
//string::iterator it1 = ss.begin();
//while (it1 != ss.end()) {
// cout << *it1 << endl;
// it1++;
//}
}
void test_string2() {
const string s("1");
s.begin();
s[0];
}
void test_string3() {
string s("hello world");
s.pushback('x');
cout << s.c_str() << endl;
s.append("yy");
cout << s.c_str() << endl;
}
void test_string4() {
string s,a;
s += '1';
a=s += "a";
cout << s.c_str() << endl;
cout << a.c_str() << endl;
}
void test_string5() {
string s("hello world");
s.insert(0, '1');
s.insert(0, '1');
s.insert(0, '1');
cout << s.c_str() << endl;
s.insert(0, "22");
cout << s.c_str() << endl;
}
void test_string6() {
string s("hello world");
size_t i = s.find('z');
cout << i << endl;
string a(s);
cout << a.c_str() << endl;
string b;
b = s;
cout << b.c_str() << endl;
}
void test_string7() {
string s("hello world");
string a("abc");
cout << s.c_str() << endl;
cout << a.c_str() << endl;
bool flag=s > a;
cout << flag << endl;
}
void test_string8() {
string s("hello world");
cout << s << endl;
cin >> s;
cout << s << endl;
}
void test_string9() {
string s("hello world");
cout << s << endl;
cin >> s;
cout << s << endl;
}
void test_string10() {
string s("hello world");
string s2(s);
cout << s2 << endl;
string s3;
s3 = s2;
cout << s3 << endl;
}
void test_string11() {
string s("hello world");
string s1("hh");
s = s1;
cout << s << endl;
}
}
int main() {
//bit::test_string2();
bit::test_string11();
return 0;
}