欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 新闻 > 焦点 > 【C++游记】string的使用和模拟实现

【C++游记】string的使用和模拟实现

2024/12/31 1:41:24 来源:https://blog.csdn.net/m0_69282950/article/details/144457813  浏览:    关键词:【C++游记】string的使用和模拟实现

 

枫の个人主页

你不能改变过去,但你可以改变未来

算法/C++/数据结构/C

Hello,这里是小枫。C语言与数据结构和算法初阶两个板块都更新完毕,我们继续来学习C++的内容呀。C++是接近底层有比较经典的语言,因此学习起来注定枯燥无味,西游记大家都看过吧~,我希望能带着大家一起跨过九九八十一难,降伏各类难题,学会C++,我会尽我所能,以通俗易懂、幽默风趣的方式带给大家形象生动的知识,也希望大家遇到困难不退缩,遇到难题不放弃,学习师徒四人的精神!!!故此得名【C++游记】

 话不多说,让我们一起进入今天的学习吧~~~ 

目录

1>>标准库的String

1.1>>auto和范围for小知识

1.2>>string常用接口(组件)这里都可以查找到

容量接口

访问和遍历

 string类对象的修改操作

非成员函数但会用到 

2>>string的模拟实现

 3>>Boos战——string重要接口的模拟实现

1.String.h

2.String.cpp 

3.wctest.cpp

4>>结语


1>>标准库的String

1.1>>auto和范围for小知识

师傅别怕,赠与“武器”一把 i

auto基本知识:

它声明引用类型时,必须在auto后加上&。

声明多个变量时,这些变量必须是相同的类型。

auto不能作为函数参数,可以作为返回值。

不能用于声明数组。

#include<iostream>
using namespace std;
int main() {auto a = 10;auto b = 'b';auto c = "asdofih";auto d = 11.11;auto& e = a;cout << a << endl;cout << b << endl;cout << c << endl;cout << d << endl;cout << e << endl;printf("%p %p", &a, &e);return 0;
}

范围for:

        对比C语言的for循环,C++使用更好用的范围for代替, 格式为:“for(auto  范围内用于迭代的变量 : 被迭代的范围)”,自动迭代、取数据、结束,这就是自动范围for。

#include<iostream>
using namespace std;
int main() {int arr[] = { 1,2,3,4,5 };for (auto& e : arr) {//若要更改里面的数值,那么就要用引用才能修改到数组本身e += 2;}for (auto e : arr) {cout << e << " ";}cout << endl;string str("hello world");for (auto ch : str) {cout << ch << " ";}cout << endl;return 0;
}

1.2>>string常用接口(组件)这里都可以查找到

师傅后面都会介绍,不必担心

String函数名称功能说明
string()构造空的string类对象,即空字符串
string(const char* s)用C-string(常量字符串)来构造string类对象
string(size_t n,char c)

string类对象中包含n个字符c

string(const string&s)

拷贝构造函数
void Test1() {string s1;//构造空的string类对象string s2("hello feng");//用常量字符串构造string类对象string s3(s2);//用s2拷贝构造s3
}

容量接口

若定义为string s,以下表size为例,就是s.size();

size返回字符串有效字符长度,使用范围比length广
length返回字符串有效字符长度
capacity返回总空间大小
empty检测字符串释放为空串,空返回true,非空返回false
clear清空有效字符
reserve为字符串预留空间
resize将有效字符个数设置为n个,多余用c填充

补充说明:size和length的区别只有在引入迭代器才能体现出来,一般都用size,length有使用限制。

clear只清空,不改大小

resize(size_t n,char c)用变量c的字符填充多余空间,resize(size_t)则是用0来填充。

reserve预留空间,小于string的空间大小时不作改动。

访问和遍历

函数名称功能说明
operator[]返回pos位置的字符,const string类对象调用
begin+endbegin获取一个字符的迭代器+end获取最后一个字符下一个位置的迭代器
rbegin+rendrbegin获取最后一个字符的迭代器+rend获取一个字符的迭代器
范围forC++11的遍历方式

 string类对象的修改操作

函数名称

功能说明

push_back在字符串后尾插字符c(单个)
append在字符串后追加一个字符串(多个)
operator+=在字符串后追加一个字符串(多个)
c_str返回C格式字符串
find+npos从字符串pos位置往后查找字符c,返回它的位置
rfind从字符串pos位置往前查找字符c,返回它的位置
substr在str中从pos位置开始,截取n个字符,将其返回

非成员函数但会用到 

函数       功能说明       
operator+深拷贝,效率低
operator>>输入运算符重载
operator<<输出运算符重载
getline获取一行字符串
relational operators大小比较

2>>string的模拟实现

错误示范:

#include<iostream>
#include<assert.h>
using namespace std;
class MyString {
public:MyString(const char* str = "") {if (str == nullptr) {perror("flase");return;}_str = new char[strlen(str) + 1];//加1放\0strcpy(_str, str);}~MyString() {if (_str) {delete[] _str;_str = nullptr;}}
private:char* _str;
};
void Test2() {string s1("hello feng");string s2(s1);
}int main() {/*Test1();*/Test2();return 0;
}

上述过程会报错,因为没有写拷贝构造,s2会调用s1的默认构造,而在类和对象章节中我们知道默认构造都是浅拷贝,这里是一个字符数组,因此要调用深拷贝。

#include<iostream>
#include<assert.h>
using namespace std;
class MyString {
public:MyString(const char* str = "") {//构造if (str == nullptr) {perror("flase");return;}_str = new char[strlen(str) + 1];//加1放\0strcpy(_str, str);}MyString(const MyString& s)//拷贝构造:_str(nullptr){MyString tmp(s._str);swap(tmp._str, _str);}~MyString() {//析构if (_str) {delete[] _str;_str = nullptr;}}
private:char* _str;
};
void Test2() {string s1("hello feng");string s2(s1);
}int main() {/*Test1();*/Test2();return 0;
}

 3>>Boos战——string重要接口的模拟实现

这里直接附上上个文件源码,大部分已经注释完毕,请大家伙享用,感兴趣可以复制过去测试,不过还是自己敲一遍比较好。

1.String.h

#pragma once#include<iostream>
#include<assert.h>
#include<string.h>
using namespace std;namespace wc
{class string{public:typedef char* iterator;//手动自造迭代器,名字与库中相同,但在wc的命名空间里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;}void swap(string& s);//交换,直接套用标准库里的swapstring(size_t n, char ch);//设置相同字符多少个为一个字符串string(const char* str = "");//构造函数string(const string& s);//拷贝构造函数~string();//析构函数void clear()//清除{_str[0] = '\0';_size = 0;}string& operator=(string s);//string& operator=(const string& s);const char* c_str() const//常数直接返回自己地址,比较快因此调用内联{return _str;}void reserve(size_t n);//保存,为字符串预留空间void push_back(char ch);//类似于尾插void append(const char* str);//尾插一个字符串string& operator+=(char ch);//类似于尾插string& operator+=(const char* str);//尾插一个字符串void insert(size_t pos, size_t n, char ch);//在pos位置插入n个ch字符void insert(size_t pos, const char* str);//在pos位置插入一个字符串void erase(size_t pos = 0, size_t len = npos);//在pos位置删除len个字符size_t find(char ch, size_t pos = 0);size_t find(const char* str, size_t pos = 0);size_t size() const{return _size;}size_t capacity() const{return _size;}char& operator[](size_t pos){assert(pos < _size);return _str[pos];}const char& operator[](size_t pos) const{assert(pos < _size);return _str[pos];}string substr(size_t pos, size_t len = npos);//从pos位置开始取len个作为子串返回bool operator==(const string& s) const;bool operator!=(const string& s) const;bool operator<(const string& s) const;bool operator<=(const string& s) const;bool operator>(const string& s) const;bool operator>=(const string& s) const;private:char* _str = nullptr;//定义字符串数组_strsize_t _size = 0;//有效个数size_t _capacity = 0;//总容量const static size_t npos;//设置默认结束值};// cout<<s1ostream& operator<<(ostream& out, const string& s);// cin>>s1istream& operator>>(istream& in, string& s);istream& getline(istream& is, string& s, char delim = '\n');void test_string1();void test_string2();void test_string3();void test_string4();void test_string5();void test_string6();void test_string7();
}

2.String.cpp 

//#include<iostream>
//using namespace std;
//int main() {
//	auto a = 10;
//	auto b = 'b';
//	auto c = "asdofih";
//	auto d = 11.11;
//	auto& e = a;
//	cout << a << endl;
//	cout << b << endl;
//	cout << c << endl;
//	cout << d << endl;
//	cout << e << endl;
//	printf("%p %p", &a, &e);
//	return 0;
//}
//#include<iostream>
//using namespace std;
//int main() {
//	int arr[] = { 1,2,3,4,5 };
//	for (auto& e : arr) {//若要更改里面的数值,那么就要用引用才能修改到数组本身
//		e += 2;
//	}
//	for (auto e : arr) {
//		cout << e << " ";
//	}
//	cout << endl;
//	string str("hello world");
//	for (auto ch : str) {
//		cout << ch << " ";
//	}
//	cout << endl;
//	return 0;
//}//void Test1() {
//	string s1;//构造空的string类对象
//	string s2("hello feng");//用常量字符串构造string类对象
//	string s3(s2);//用s2拷贝构造s3
//}
//#include<iostream>
//#include<assert.h>
//using namespace std;
//class MyString {
//public:
//	MyString(const char* str = "") {//构造
//		if (str == nullptr) {
//			perror("flase");
//			return;
//		}
//		_str = new char[strlen(str) + 1];//加1放\0
//		strcpy(_str, str);
//	}
//	MyString(const MyString& s)//拷贝构造
//		:_str(nullptr)
//	{
//		MyString tmp(s._str);
//		swap(tmp._str, _str);
//	}
//	~MyString() {//析构
//		if (_str) {
//			delete[] _str;
//			_str = nullptr;
//		}
//	}
//private:
//	char* _str;
//};
//void Test2() {
//	string s1("hello feng");
//	string s2(s1);
//}
//
//int main() {
//	/*Test1();*/
//	Test2();
//	return 0;
//}#define _CRT_SECURE_NO_WARNINGS 1
#include"string.h"namespace wc
{const size_t string::npos = -1;void string::swap(string& s){std::swap(_str, s._str);std::swap(_size, s._size);std::swap(_capacity, s._capacity);}string::string(size_t n, char ch):_str(new char[n + 1]), _size(n),_capacity(n){for (size_t i = 0; i < n; i++) {_str[i] = ch;}_str[_size] = '\0';}string::string(const char* str)//声明中写过默认值,这里就不能再写了 :_size(strlen(str)){_capacity = _size;_str = new char[_size + 1];strcpy(_str, str);//复制还没复制\0_str[_size] = '\0';}string::string(const string& s){string tmp(s._str);swap(tmp);}string::~string(){delete[] _str;_str = nullptr;_size = 0;_capacity = 0;}string& string::operator=(string s) {swap(s);return *this;}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 + 1 > _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);}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, size_t n, char ch){assert(pos <= _size);assert(n > 0);if (_size + n > _capacity){// 扩容size_t newCapacity = 2 * _capacity;if (_size + n > 2 * _capacity){newCapacity = _size + n;}reserve(newCapacity);}size_t end = _size + n;while (end > pos + n - 1) {_str[end] = _str[end - n];end--;}for (size_t i = 0; i < n; i++) {_str[pos + i] = ch;}_size += n;}void string::insert(size_t pos, const char* str){size_t n = strlen(str);insert(pos, n, 'x');//覆盖一下for (size_t i = 0; i < n; i++){_str[pos + i] = str[i];}}void string::erase(size_t pos, size_t len) {if (len > _size - pos) {//多删了_str[pos] = '\0';_size = pos;}else {size_t end = pos + len;while (end <= _size) {//\0也拷贝_str[end - len] = _str[end];end++;}_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){const char* p = strstr(_str + pos, str);if (p == nullptr){return npos;}else{return p - _str;}}string string::substr(size_t pos, size_t len){if (len > _size - pos)//若超出,就等于剩下长度len = _size - pos;string tmp;tmp.reserve(len);for (size_t i = 0; i < len; i++) {tmp += _str[pos + i];//直接加等,简单易懂}return tmp;}bool string::operator==(const string& s) const{return strcmp(_str, s._str) == 0;}bool string::operator!=(const string& s) const{return !(*this == s);}bool string::operator<(const string& s) const{return strcmp(_str, s._str) < 0;}bool string::operator<=(const string& s) const{return *this < s || *this == s;}bool string::operator>(const string& s) const{return !(*this <= s);}bool string::operator>=(const string& s) const{return !(*this < s);}ostream& operator<<(ostream& out, const string& s){for (size_t i=0;i<s.size();i++){out << s[i];}return out;}istream& operator>>(istream& in, string& s){s.clear();// 输入短串,不会浪费空间// 输入长串,避免不断扩容const size_t N = 1024;char buff[N];int i = 0;char ch = in.get();while (ch != ' ' && ch != '\n')//遇到空格和\n停止{buff[i++] = ch;if (i == N - 1){buff[i] = '\0';//最后一个复制为0然后加上s += buff;i = 0;}//也可以直接写s+=ch,不过占用内存高ch = in.get();}if (i > 0){buff[i] = '\0';s += buff;}return in;}istream& getline(istream& in, string& s, char delim){s.clear();const size_t N = 1024;char buff[N];int i = 0;char ch = in.get();while (ch != delim){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;}void test_string1(){string s1("hello world");cout << s1.c_str() << endl;string s2;cout << s2.c_str() << endl;s1 += ' ';s1 += '+';s1 += "hello ";s1 += "hello feng1111111111111111111111111";cout << s1.c_str() << endl;}void test_string2(){string s1("hello world");cout << s1.c_str() << endl;s1.insert(11, 3, 'x');cout << s1.c_str() << endl;s1.insert(6, 3, 'x');cout << s1.c_str() << endl;s1.insert(0, 3, 'x');cout << s1.c_str() << endl;string s2("hello world");cout << s2.c_str() << endl;s2.insert(11, "yyy");cout << s2.c_str() << endl;s2.insert(6, "yyy");cout << s2.c_str() << endl;s2.insert(0, "yyy");cout << s2.c_str() << endl;}void test_string3(){string s1("hello world");cout << s1.c_str() << endl;s1.erase(6, 2);cout << s1.c_str() << endl;s1.erase(6, 20);cout << s1.c_str() << endl;s1.erase(3);cout << s1.c_str() << endl;string s2("hello helleoo");cout << s2.find('e') << endl;cout << s2.find("helle") << endl;}void test_string4(){string s1("hello world");for (size_t i = 0; i < s1.size(); i++){s1[i]++;cout << s1[i] << " ";}cout << endl;string::iterator it = s1.begin();while (it != s1.end()){cout << *it << " ";++it;}cout << endl;for (auto e : s1){cout << e << " ";}cout << endl;const string s2("hello world");for (auto e : s2){cout << e << " ";}cout << endl;}void test_string5(){string s1("hello world");string sub1 = s1.substr(6, 3);cout << sub1.c_str() << endl;string sub2 = s1.substr(6, 300);cout << sub2.c_str() << endl;string sub3 = s1.substr(6);cout << sub3.c_str() << endl;string s2("hello fengxxxxxxxxxxxxxxxxxx");s1 = s2;cout << s1.c_str() << endl;cout << s2.c_str() << endl;s1 = s1;cout << s1.c_str() << endl;}void test_string6(){/*string s1("hello world");string s2("hello bit");cout << s1 << endl;cout << s2 << endl;string s3;cin >> s3;cout << s3 << endl;*/string s1, s2;cin >> s1 >> s2;cout << s1 << endl;cout << s2 << endl;string s3;//getline(cin, s3);getline(cin, s3, '!');cout << s3 << endl;}void test_string7(){string s1("1111111111111");string s2(s1);cout << s1 << endl;cout << s2 << endl;string s3("222222222222222222222222222");s1 = s3;cout << s1 << endl;cout << s3 << endl;//s1.swap(s2);//swap(s1, s2);cout << s1 << endl;cout << s2 << endl;}
}

3.wctest.cpp

#include"string.h"int main()
{//wc::test_string1();//wc::test_string3();wc::test_string5();return 0;
}

4>>结语

        今日C++到这里就结束啦,如果觉得文章还不错的话,可以三连支持一下。感兴趣的宝子们欢迎持续订阅小枫,小枫在这里谢谢宝子们啦~小枫の主页还有更多生动有趣的文章,欢迎宝子们去点评鸭~C++的学习很陡,时而巨难时而巨简单,希望宝子们和小枫一起坚持下去~你们的三连就是小枫的动力,感谢支持~

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com