C++:string

二十五·夜 2024-09-07 11:35:22 阅读 96

1.STL简介

STL(standard template library标准模版库),是c++标准库的重要组成部分,是一个包罗数据结构与算法的软件框架

STL有很多版本,我们学习STL要阅读部分源代码,主要参考SGI版本。

STL的六大组件

网上有句话说:“不懂STL,不要说你会C++”。STL是C++中的优秀作品,有了它的陪伴,许多底层 的数据结构以及算法都不需要自己重新造轮子,站在前人的肩膀上,健步如飞的快速开发。

2.string类

string属于c++标准库,诞生比STL早,在广义的角度,string也属于容器。

在string内种有一百多种函数,我们只需要掌握重要的就行了。

学习这部分知识我们需要学会查字典

https://cplusplus.com

使用string类要包头文件#inlucde<string>,还有using namespace std;

 constructor(构造):

<code>string s1;//空的

string s2("hello world");

string s3(s2);

cout << s1 << endl;//

cout << s2 << endl;//hello world

cout << s3 << endl;//hello world

//string类中有流插入和流提取的函数

 第三个是在给定的类中的第pos位置,开始复制npos数个。

<code>string s4(s2, 6, 5);//world

//如果len的长度大于后面字符的长度,只复制到字符串结束

第五个是给定的字符串,复制n个。

string s6("hello world", 5);//hello

第六个是给类构造n个字符、

string s7(10, 'c');

cout << s7<< endl;//cccccccccc

 

这个函数的目的就是能修改对象的字符串中的字符。

<code>s6[0] = 'x';

cout << s6;//xello

 三种方法遍历string类的对象:

//下标+[]

string s("hello world");

for(size_t i=0;i<s.size();i++)

{

cout<<s[i];

}

cout<<endl;

//迭代器

string::iterator it=s.begin();//iterator像指针的东西

while(it!=s.end())//s.end()指向最后一个位置的下一个位置

{

//使用迭代器也可修改

//*it+=2;

cout<<*it;//*是运算符重载

it++;

}

//任何容器都可以用迭代器来访问

//范围for 底层就是迭代器

for(auto ch:s);//auto在c++中是自动推导。自动赋值,自动迭代,自动判断

{

ch+=2;//打印后是每个字符加2的结果,但s没变,还是原来的字符。

//要想变的话,在auto后面加&

cout<<ch;

}

cout<<endl;

auto:

这不是string里面的用法,这里来介绍一下auto的用法.

用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须加&当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际 只对第一个类型进行推导,然后用推导出来的类型定义其他变量。auto不能作为函数的参数,可以做返回值,但是建议谨慎使用auto不能直接用来声明数组

int func()

{

return 10;

}

int main()

{

int a = 10;

auto b=a;

auto c = 'a';

auto d = func();

//"auto"的符号必须具有初始值设定项

//auto e;

cout << typeid(a).name() << endl;

cout << typeid(c).name() << endl;

cout << typeid(d).name() << endl;

//范围for适用于容器和数组

int array[] = { 1,2,3,4,5 };

//C++98的遍历

for (int i = 0; i < sizeof(array) / sizeof(int); i++)

{

array[i] *= 2;

}

for (int i = 0; i < sizeof(array) / sizeof(int); i++)

{

cout << array[i] << endl;

}

//C++

for (auto& e : array)

e *= 2;

for (auto& e : array)

cout << e << " " << endl;

}

auto可以缩短代码,比如:

map<string, string> dict;

//map<string, string>::iterator mit = dict.begin();

auto mit = dict.begin();

iterator:

begin和end在上面已经见识到了,那我们来看看rbegin,rend。

//反向迭代器

string::reverse_iterator rit = s1.rbegin();//rbegin指向最后一个字符

while (rit != s1.rend())//rend指向第一个字符的前一个

{

cout << *rit << " ";//d l r o w o l l e h

++rit;

}

cout << endl;

反过来遍历。

 看到下面还有const_iterator begin() const,这里是让对象只可读不可改,所以我们迭代器有四种类型。

<code>const string s2("hello world");

string::const_iterator cit = s2.begin();

while (cit != s2.end())

{

cout << *cit << " ";

++cit;

}

string::const_reverse_iterator crit = s2.rbegin();

//auto crit = s2.rbegin();

while (crit != s2.rend())

{

cout << *crit << " ";

++crit;

}

 cbegin,cend返回的是被const修饰的迭代器,指向字符串,不能修改。只是与对象被const的作区分。

capacity:

size()与length()的效果一样,但length还是有局限性。一般都用size()。

max_size()是string对象所能达到的最大的长度。

resize()是改变对象的长度。对象的容量不变。

 第二个用法就是长度变长后,字符c填充到新的空间。

<code>string str("I like to code in C");

cout << str << '\n';

unsigned sz = str.size();

str.resize(sz + 2, '+');

cout << str << '\n';//I like to code in C++

str.resize(14);

cout << str << '\n';//I like to code

 capacity(),容量,在vs上长度小于等于15时,容量为15。这是因为string底层有一个数组buf[16],最后一个存\0,如果数据长度小于15,存在buf上,不存在str上,大于15时,存在str开辟的堆空间上,buf就不存数据。如果在对象后面追加字符,容量会自动扩容。

class string

{

private:

char buf[16];

char*_str;

int _size;

int _capacity;

};

 reserve(),是给容量开好空间(可以提前开),但空间大小大于等于给的数据。假如开的过多,容量不会缩容。假如开的不够,容量会自动扩。

clear(),清除数据,但不清除容量。

empty()是来判断字符串是否为常量。

 shrink_to_fit(),是用来缩容到合适的大小,避免空间浪费。

 在vs上调试能看到这些东西:

Modifiers:

operator+=,append,push_back都是尾插,一般用的最多的是+=。

push_back只能尾插字符

<code>int main()

{

string s("hello world");

s.push_back(' ');

s.push_back('#');

cout<<s<<endl;//hello world #

return 0;

}

 

append可以尾插字符串,这些如果要用到,查一下就好了。

<code>int main()

{

string s("hello world");

s.push_back(' ');

s.push_back('#');

cout<<s<<endl;//hello world #

s.append("xyz");

cout<<s<<endl;//hello world #xyz

return 0;

}

 

<code>int main()

{

string s("hello world");

s.push_back(' ');

s.push_back('#');

cout<<s<<endl;//hello world #

s.append("xyz");

cout<<s<<endl;//hello world #xyz

s+='$';

cout<<s<<endl;//hello world #xyz$

return 0;

}

 insert插入,在指定位置插入字符或字符串

erase删除,删除一部分字符串,来减小长度。

string s("hello world");

s.erase(0, 1);//头删

cout << s << endl;//ello world

s.erase(s.begin());llo world

cout << s << endl;

//尾删

s.erase(--s.end());

cout << s << endl;

s.erase(s.size() - 1, 1);

cout << s << endl;

string ss("hello world");

ss.erase(6);//hello

 replace,将字符串的字符替换成字符或字符串。

string sss("hello world hello world");

size_t pos = sss.find(' ');

while (pos != string::npos)

{

sss.replace(pos, 1, "%%");

pos = sss.find(' ',pos+2);

}

cout << sss << endl;//hello%%world%%hello%%world

swap(),交换两个对象的内容。

String operations:

c_str(),就是获得对象的_str(字符串)。

find,就是找字符或字符串,返回下标,rfind就是倒着找。

substr就是生成一个子字符串

<code>string s("test.cpp.zip");

size_t pos = s.rfind('.');

string suffix = s.substr(pos);

cout << suffix << endl;//.zip

 Member constants:

npos:

 当在字符串的成员函数中用作 len(或 sublen)参数的值时,此值表示“直到字符串的末尾”。

作为返回值,它通常用于指示不匹配。

此常量使用值 -1 定义,由于size_t是无符号整数类型,因此它是此类型的最大可能可表示值。

 getline:

第一种是,输入字符,直到遇到字符delim为止,第二种是'\n'表示终止,可以识别空格。

3.模拟实现string底层

string.h:

<code>#pragma once

#define _CRT_SECURE_NO_WARNINGS 1

#include<iostream>

#include<assert.h>

using namespace std;

namespace byh

{

class string

{

public:

typedef char* iterator;

typedef const char* const_iterator;

iterator begin()

{

return _str;

}

iterator end()

{

return _str+_size;

}

const_iterator begin()const

{

return _str;

}

const_iterator end()const

{

return _str+_size;

}

/*string()

:_str(new char[1] {'\0'})

, _size(0)

, _capacity(0)

{}*/

//短小频繁调用的函数,可以直接定义到类里面,默认是inline

string(const char* str="")code>

{

_size = strlen(str);

//_capacity不包含\0

_capacity = _size;

_str = new char[_capacity + 1];

strcpy(_str, str);

}

//深拷贝问题

string(const string& s)

{

_str = new char[s._capacity + 1];

strcpy(_str, s._str);

_size = s._size;

_capacity = s._capacity;

}

string& operator=(const 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;

}

~string()

{

delete[]_str;

_str = nullptr;

_size = _capacity = 0;

}

const char* c_str()const

{

return _str;

}

size_t size()const

{

return _size;

}

size_t capacity()const

{

return _capacity;

}

void clear()

{

_str[0] = '\0';

_size = 0;

}

char& operator[](size_t pos)

{

assert(pos < _size);

return _str[pos];

}

const char& operator[](size_t pos)const

{

assert(pos < _size);

return _str[pos];

}

void push_back(char ch);

void append(const char* str);

string& operator+=(char ch);

string& operator+=(const char* str);

void reserve(size_t n);

void insert(size_t pos, char ch);

void insert(size_t pos, const char* str);

void erase(size_t pos, size_t len=npos);

size_t find(char ch, size_t pos = 0);

size_t find(const char* str, size_t pos=0);

string substr(size_t pos = 0, size_t len = npos);

private:

char* _str;

size_t _size;

size_t _capacity;

static const size_t npos;

//static const size_t npos=-1;这样也行

};

bool operator<(const string& s1, const string& s2);

bool operator<=(const string& s1, const string& s2);

bool operator>(const string& s1, const string& s2);

bool operator>=(const string& s1, const string& s2);

bool operator==(const string& s1, const string& s2);

bool operator!=(const string& s1, const string& s2);

ostream& operator<<(ostream& out, const string& s);

istream& operator>>(istream& in, string& s);

}

string.cpp:

#include"string.h"

namespace byh

{

const size_t string::npos = -1;

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';

}

void string::append(const char* str)

{

size_t len = strlen(str);

if (_size + len > _capacity)

{

//大于二倍,需要多少开多少

reserve(_size + len > 2 * _capacity ? _size + len : 2 * _capacity);

}

strcpy(_str + _size, str);

_size += len;

}

string& string::operator+=(char ch)

{

push_back(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)

{

reserve(_capacity == 0 ? 4 : _capacity * 2);

}

//挪动数据

/*int end = _size;

while (end>=(int)pos)

{

_str[end + 1] = _str[end];

--end;

}

_str[pos] = ch;

_size++;*/

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 (len == 0)

return;

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);

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;

}

}

size_t string::find(char ch, size_t pos)

{

for (size_t i = pos; i < _size; i++)

{

if (_str[i] == ch)

{

return i;

}

}

return npos;

}

size_t string::find(const char* str, size_t pos)

{

assert(pos < _size);

const char* ptr = strstr(_str + pos, str);

if (ptr == nullptr)

{

return npos;

}

else

{

return ptr - _str;

}

}

string string::substr(size_t pos, size_t len)

{

assert(pos < _size);

//len大于剩余字符长度,更新一下len

if (len > _size - pos)

{

len = _size - pos;

}

string sub;

sub.reserve(len);

for (size_t i = 0; i < len; i++)

{

sub += _str[pos + i];

}

return sub;

}

bool operator<(const string& s1, const string& s2)

{

return strcmp(s1.c_str(), s2.c_str()) < 0;

}

bool operator<=(const string& s1, const string& s2)

{

return s1 < s2 || s1 == s2;

}

bool operator>(const string& s1, const string& s2)

{

return !(s1 <= s2);

}

bool operator>=(const string& s1, const string& s2)

{

return !(s1 < s2);

}

bool operator==(const string& s1, const string& s2)

{

return strcmp(s1.c_str(), s2.c_str()) == 0;

}

bool operator!=(const string& s1, const string& s2)

{

return !(s1 == s2);

}

ostream& operator<<(ostream& out, const string& s)

{

for (auto ch : s)

{

out << ch;

}

return out;

}

istream& operator>>(istream& in, string& s)

{

s.clear();

const int N = 256;

char buff[N];

int i = 0;

char ch;

ch = in.get();

while (ch != ' ' && ch != '\n')

{

buff[i++] = ch;

if (i == N - 1)

{

buff[i] = '\0';

s += buff;

i = 0;

}

ch = in.get();

}

if (i > 0)

{

buff[i] = '\0';

s += buff;

}

return in;

}

}

test.cpp:

#include"string.h"

using namespace std;

namespace byh

{

void test_string1()

{

string s1;

string s2("hello world");

cout << s1.c_str() << endl;

cout << s2.c_str() << endl;

for (size_t i = 0; i < s2.size(); i++)

{

s2[i] += 2;

}

cout << s2.c_str() << endl;

for (auto ch : s2)

{

cout << ch;

}

cout << endl;

string::iterator it = s2.begin();

while (it != s2.end())

{

//*it += 2;

cout << *it << " ";

++it;

}

cout << endl;

}

void test_string2()

{

string s1("hello world");

s1 += 'x';

s1 += '#';

cout << s1.c_str() << endl;

s1 += "ye";

cout << s1.c_str() << endl;

s1.insert(0, '$');

cout << s1.c_str() << endl;

s1.insert(6, "$$$");

cout << s1.c_str() << endl;

}

void test_string3()

{

string s1("hello world");

s1.erase(6, 100);

cout << s1.c_str() << endl;

string s2("hello world");

s2.erase(6);

cout << s2.c_str() << endl;

string s3("hello world");

s3.erase(6, 3);

cout << s3.c_str() << endl;

}

void test_string4()

{

string s1("test.cpp.zip");

size_t pos = s1.find('.');

string suffix = s1.substr(pos);

cout << suffix.c_str() << endl;

}

void test_string5()

{

string s1("hello world");

string s2("hello world");

cout << (s1 < s2) << endl;

cout << (s1 == s2) << endl;

cout << ("hello world" == s2) << endl;

cout << (s1 > "hello") << endl;

//cout<<("hello"=="hello")<<endl;

cout << s1 << s2 << endl;

string s0;

cin >> s0;

cout << s0 << endl;

}

}

int main()

{

//byh::test_string1();

byh::test_string5();

return 0;

}

完,感谢观看。



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。