文章目录
前言
我们在C语言中学习了字符串(用双引号引起的以’/0’结尾的一串字符),并提供了字符串库函数的使用,但为了更好的使用,C++中分封装了字符串的类——string,提高效率。接下来我们看看string的相关知识。🚗
1、标准库中string介绍
2、string的构造函数使用
主要是默认的无参构造函数、拷贝构造函数、从原来的string对象拷贝新对象等。
3、string访问方式
下面是下标+[ ]遍历、迭代器遍历、范围for遍历:
int main()
{
string s1("Hello Word!");
//下标[]访问:
cout << s1[0] << endl;
//下标+[]遍历
for (int i = 0; i < s1.size(); i++)
{
cout << s1[i] << " ";
}
cout << endl;
//迭代器访问
string::iterator it = s1.begin();
while (it != s1.end())
{
cout << *it << " ";
++it;
}
cout << endl;
//范围for访问,auto自动推导s1的类型,自动迭代、自动判断结束
for (auto ch : s1)
{
cout << ch << " ";
}
cout << endl;
return 0;
}
4、string常用的接口描述
4.1 string类对象常见的构造
函数名 | 作用 |
---|---|
string() | 默认构造函数,构造空的string类——空字符 |
string(const char* s) | 用已经有的string对象来构造string新对象 |
string(const string &s) | 拷贝构造函数 |
string(size_t n,char c) | 构造一个包含n个字符c |
int main()
{
string s1;
string s2("STL Hello!");
string s3(s2);
string s4(5, 'M');
cout << s1 << endl;
cout << s2 << endl;
cout << s3 << endl;
cout << s4 << endl;
return 0;
}
4.2string类对象的容量操作
函数名称 | 功能说明 |
---|---|
size | 返回字符串有效字符长度 |
length | 返回字符串有效字符长度 |
capacity | 返回空间总大小 |
empty | 检测字符串释放为空串,是返回true,否则返回false |
clear | 清空有效字符 |
reserve | 为字符串预留空间** |
resize | 将有效字符的个数改成n个,多出的空间用字符c填充 |
注意:
①size()和length()方法实现的原理完全相同。
②clear操作后,只是把数据清空为0,空间大小不会改变;
③resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个;区别在于当字符个数增多时:
resize(n)用0来填充多出的元素空间;
resize(size_t n, charc)用字符c来填充多出的元素空间。
注意:resize在改变元素个数时,如果是将元素个数增多,
可能会改变底层容量的大小,如果是将元素个数减少,
底层空间总大小不变。
④ reserve(size_t res_arg=0):为string预留空间,不改变有效元素个数,当reserve的参数小于string的底层空间总大小时,reserver不会改变容量大小。
大小空间的使用:
int main()
{
//size()和length()是一样的实现原理
string str1("hello C++ programmer");
cout << "str1的size:" << str1.size() << "\n";
cout << "str1的length:" << str1.length() << "\n";
cout << "str1的容量capacity:" << str1.capacity() << "\n";
cout << "使用clear清空后,不会改变容量大小:"<<endl;
str1.clear();
cout << "str1的容量capacity:" << str1.capacity() << "\n";
return 0;
}
5、string类的模拟实现
String.h短小或频繁调用的函数就直接写在类里面
#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include<iostream>
#include<string>
#include<cassert>
using namespace std;
namespace zc
{
class String
{
friend ostream& operator<<(ostream& _cout, const zc::String& s);
friend istream& operator>>(istream& _cin, zc::String& s);
public:
typedef char* iterator;
public:
无参构造函数,初始化列表实现
//String()
// :_str(new char[1] {'\0'})
// , _size(0)
// ,_capacity(0)
//{}
带参构造函数
//String(const char* str)
//{
// _size = strlen(str);
// _capacity = _size;
// _str = new char[_capacity + 1];//因为不包含\0,因此多开一个空间
// strcpy(_str,str);
//}
//直接合并写为全缺省构造函数
String(const char* str="")
{
_size = strlen(str);
_capacity = _size;
_str = new char[_capacity + 1];
strcpy(_str,str);
}
//拷贝构造函数
String(const String& str)
{
_str = new char[str._capacity + 1];
strcpy(_str,str._str);
_size = str._size;
_capacity = str._capacity;
}
String& operator=(const String& str)
{
delete[] _str;
_str = new char[str._capacity+1];
strcpy(_str, str._str);
_size = str._size;
_capacity = str._capacity;
return *this;
}
//析构函数
~String()
{
delete[] _str;
_str = nullptr;
_size = _capacity = 0;
}
const char* c_str() const
{
return _str;
}
/*^^^^^^^^^^^^^^^^^^^^^^^^*/
//capacity的相关函数
size_t size()const
{
return _size;
}
size_t capacity()const
{
return _capacity;
}
bool empty()const
{
return _size == 0;
}
void reserve(size_t n);
/*^^^^^^^^^^^^^^^^^^^^^^^^*/
//access(访问相关函数)
//可修改的[]访问
char& operator[](size_t index)
{
assert(index>=0);
return _str[index];
}
//只读不写
const char& operator[](size_t index)const
{
assert(index>=0);
return _str[index];
}
/*^^^^^^^^^^^^^^^^^^^^^^^^*/
//iterator迭代器相关函数
iterator begin()
{
return _str;
}
iterator end()
{
return _str + _size;
}
/*^^^^^^^^^^^^^^^^^^^^^^^^*/
//modify相关函数
void push_back(char ch);
String& operator+=(char ch);
void append(const char* str);
String& operator+=(const char* str);
void clear();
/*^^^^^^^^^^^^^^^^^^^^^^^^*/
//relational operators
bool operator<(const String& s)
{
return strcmp(this->_str, s.c_str())<0;
}
bool operator<=(const String& s)
{
return (*this == s) || (*this< s);
}
bool operator>(const String& s)
{
return !(*this <= s);
}
bool operator>=(const String& s)
{
return !(*this < s);
}
bool operator==(const String& s)
{
return strcmp(this->_str,s.c_str())==0;
}
bool operator!=(const String& s)
{
return !(*this == s);
}
// 返回c在string中第一次出现的位置
size_t find(char c, size_t pos = 0) const;
// 返回子串s在string中第一次出现的位置
size_t find(const char* s, size_t pos = 0) const;
void insert(size_t pos, char ch);
void insert(size_t pos, const char* str);
void erase(size_t pos,size_t len=npos);
String substr(size_t pos, size_t len = npos);
private:
char* _str;
size_t _size;
size_t _capacity;
const static size_t npos = -1;
};
ostream& operator<<(ostream& _cout, const zc::String& s);
istream& operator>>(istream& _cin, zc::String& s);
void Test_string();
}
String.cpp
#include "String.h"
namespace zc
{
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::push_back(char ch)
{
//扩容机制
if (_size == _capacity)
{
reserve(_capacity==0?4:_capacity*2);
}
_str[_size] = ch;
++_size;
_str[_size] = '\0';
}
String& String::operator+=(char ch)
{
push_back(ch);
return *this;
}
void String::append(const char* str)
{
size_t len = strlen(str);
if (_size + len > _capacity)
{
reserve(_size + len > _capacity * 2 ? _size + len : _capacity * 2);
}
strcpy(_str+_size,str);
_size += len;
}
String& String::operator+=(const char* str)
{
append(str);
return *this;
}
void String::clear()
{
_str[0] = '\0';
_size = 0;
}
size_t String::find(char c, size_t pos) const
{
assert(pos<=_size&&pos>=0);
for (size_t i = pos; i < _size; i++)
{
if (_str[i] == c)
{
return i;
}
}
return pos;
}
size_t String::find(const char* s, size_t pos) const
{
assert(pos<_size);
const char* ptr = strstr(_str + pos, s);
if (ptr == nullptr)
{
return npos;
}
else
{
return ptr - _str;
}
}
void String::insert(size_t pos, char ch)
{
//检查位置是否合法
assert(pos>=0&&pos<=_size);
//空间
if (_size == _capacity)
{
reserve(_capacity==0?4:_capacity*2);
}
插入
//int end = _size;
//while (end >= (int)pos)//存在类型自动转换,因为pos是size_t无符号,因此需要强转
//{
// //移动
// _str[end + 1] = _str[end];
// --end;
//}
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 >= 0 && pos <= _size);
//空间
size_t len = strlen(str);
if (_size+len > _capacity)
{
reserve(_size+len>2*_capacity?_size+len:2*_capacity);
}
size_t end = _size + len;
while (end>pos+len-1)
{
_str[end] = _str[end - len];
--end;
}
for (size_t i = 0; i < len; i++)
{
_str[pos + i] = str[i];
}
_size += len;
}
void String::erase(size_t pos, size_t len)
{
assert(pos<=_size&&pos>=0);
if (len >= _size - pos)
{
//所要删除数据的长度大于后面剩余数据的长度,就全部删除
_str[pos] = '\0';
_size = pos;
}
else
{
//按所给的长度删除,需要挪动数据
for (size_t i = pos + len; i <= _size; i++)
{
_str[i - len] = _str[i];
}
//改变长度
_size -= len;
}
}
String String::substr(size_t pos, size_t len)
{
assert(pos <= _size && pos >= 0);
//len大于剩余长度就更新
if (len > _size - pos)
{
len = _size - pos;
}
String sub;
reserve(len);
for (int i = 0; i < len; i++)
{
sub += _str[pos + i];
}
return sub;
}
ostream& operator<<(ostream& _cout, const zc::String& s)
{
for (size_t i = 0; i < s.size(); ++i)
{
_cout << s[i];
}
return _cout;
}
istream& operator>>(istream& _cin, zc::String& s)
{
s.clear();
/* char ch=_cin.get();
while (ch !=' ' && ch != '\n')
{
s += ch;
ch = _cin.get();
}*/
const int N = 256;
char buff[N];
int i = 0;
char ch;
ch=_cin.get();
while (ch != ' ' && ch != '\n')
{
buff[i++] = ch;
if (i == N - 1)
{
buff[i] = '\0';
s += buff;
i = 0;
}
ch = _cin.get();
}
if (i > 0)
{
buff[i] = '\0';
s += buff;
}
return _cin;
}
}
test.cpp测试源文件
#define _CRT_SECURE_NO_WARNINGS 1
#include"String.h"
namespace zc
{
void zc::Test_string()
{
String s1;
String s2("hello C++ programmer!");
cout << s1.c_str() << endl;
cout << s2.c_str() << endl;
cout << "s1大小:" << s1.size() << endl;
cout << "s2大小:" << s2.size() << endl;
cout << "s1空间:" << s1.capacity() << endl;
cout << "s2空间:" << s2.capacity() << endl;
cout << "s1是否为空:" << s1.empty() << endl;
cout << "s2是否为空:" << s2.empty() << endl;
cout << endl;
cout << "s2清除后:" << endl;
s2.clear();
cout << "s2大小:" << s2.size() << endl;
cout << "s2空间:" << s2.capacity() << endl;
cout << "s2是否为空:" << s2.empty() << endl;
String s3("hello word");
for (auto ch : s3)
{
cout << ch << " ";
}
cout << endl;
/* String::iterator it = s3.begin();
while (it != s3.end())
{
cout << *it << " ";
++it;
}
cout << endl;*/
s3[0] = 'H';
s3[6] = 'W';
for (int i = 0; i < s3.size(); i++)
{
cout << s3[i] << " ";
}
cout << endl;
s3.push_back('C');
cout << s3.c_str() << endl;
s3 += 'F';
cout << s3.c_str() << endl;
s3.append("string");
cout << s3.c_str() << " ";
cout << endl;
s3 += "zhou";
cout << s3.c_str() << " ";
cout << endl;
String s4("word");
cout << s4.c_str() << endl;
//s4.insert(0, 'm');
s4.insert(4, '!');
cout << s4.c_str() << endl;
s4.insert(0, "hello ");
cout << s4.c_str() << endl;
s4.erase(6,3);
cout << s4.c_str() << endl;
s4.erase(4);
cout << s4.c_str() << endl;
String s5("C++ programmer!");
cout << s5.c_str() << endl;
size_t pos=s5.find('p');
String str = s5.substr(pos);
cout << str.c_str() << endl;
String s6("C++");
cout << s6.c_str() << endl;
s5 = s6;
cout << s5.c_str() << endl;
String s7("C++");
cout << (s6 == s7) << endl;
cout << s6 << endl;
String s8;
cin >> s8;
cout << s8 << endl;
}
}
int main()
{
zc::Test_string();
return 0;
}