您的位置:首页 > 房产 > 家装 > 找平面设计师网站_短视频广告分析_做网站优化哪家公司好_谷歌浏览器下载视频

找平面设计师网站_短视频广告分析_做网站优化哪家公司好_谷歌浏览器下载视频

2024/10/6 12:27:58 来源:https://blog.csdn.net/m0_73399947/article/details/142432662  浏览:    关键词:找平面设计师网站_短视频广告分析_做网站优化哪家公司好_谷歌浏览器下载视频
找平面设计师网站_短视频广告分析_做网站优化哪家公司好_谷歌浏览器下载视频

欢迎来到本期节目- - -

string类

以下列举的是string类的常用接口,详情查看cplusplus
在这里插入图片描述

构造函数的使用:

以下是string类对象最常见的构造方式

#include<string>
using namespace std;void test1()
{string str1;	//调用默认构造函数,构造一个空字符串string str2("I am string");	//调用带参构造,参数是c格式字符串string str3(str2);		//调用拷贝构造
}

容器方法的使用:

以下是常用的方法

#include<iostream>
#include<string>
using namespace std;void test2()
{string str("I am string");cout << str.size() << endl;  	//返回字符串的有效长度cout << str.capacity() << endl; 	//返回字符串当前的空间总大小(>=字符串的总长度)cout << str.clear() << endl;	//清空有效字符, 不影响字符串的容量空间cout << str.empty() << endl;	//判断字符串是否为空字符串cout << str.resize(20,'x') << endl;		//把有效字符个数改为20个,多出的空间用'x'填充cout << str.reserve(30) << endl; 	//让字符串的空间容量至少为30个有效字符.
}

注意:

	void resize (size_t n);void resize (size_t n, char c);
n是用户需要的有效字符长度;
c是用户需要的指定字符;
当n小于实际的有效字符长度时,该函数只会保留前n个字符,删除其余字符.
当n大于实际的有效字符长度时,该函数会将多出来的空间用c填充,如果未指定,则填充空字符.(可能会扩容)
	void reserve(size_t n = 0);
n是用户期望的容量大小;
当n小于字符串实际的容量大小,没有明确的规定要不要缩容,但是绝不会影响到字符串的有效长度.
当n大于字符串实际的容量大小,字符串的容量至少扩容到能存储n个有效字符。(实际开了n+1个,为了存空字符)

查找方法的使用:

以下是常用的方法

#include<iostream>
#include<string>
using namespace std;void test3()
{string str("test");//打印字符的方式for(int i = 0; i < str.size(); i++){cout << str[i] << " ";	//str.operator[](i)}cout << endl;//打印字符串的方式cout << str.c_str() << endl;	//该方法返回的是c格式字符串的首地址str += ".cpp";	//添加字符串size_t pos = str.find('.');		//在字符串中正向查找'.' 找到后返回第一个出现该字符的位置if(pos == string::npos)		//没找到返回npos实际上npos=-1{cout << "未找到\n" << endl;return ;}cout << "后缀名是:" << endl;cout << str.c_str()+pos << endl;	//找到了,打印后缀}

推荐

string& operator+= (const string& str);
string& operator+= (const char* s);
string& operator+= (char c);
operator+=是最常用的接口,因为不仅方便,而且可读性强,代码简洁。

非类成员使用

#include<iostream>
#include<string>
using namespace std;void test()
{string str;cin >> str;		//流插入,从标准流提取单词输入到字符串中,因为空格为分隔符cout << str << endl;	//流提取,把字符串输出到屏幕上//如果想要输入一行文本getline(cin,str);	//遇到换行符提取并丢弃,然后停止读取cout << str << endl;
}

注意:

cin和scanf在读取单词之后遇到分隔符会停止读取,最后的分割符还在缓冲区.
istream& getline (istream& is, string& str, char delim);	
istream& getline (istream& is, string& str);
delim是终止符;
getline遇到指定的delim,就提取并丢弃然后停止读取.
否则遇到换行符,提取并丢弃然后停止读取.

string类的结构

尽管在不同的环境下,string类的功能都是一样的,但是底层的结构可能不一样:
以下以32位平台为例:

在vs2019中

string类
共用体
size_t字段存长度
size_t字段存容量
指针
value_type _Buff[_BUF_SIZE]
pointer _Ptr
char _Alias[_BUF_SIZE]

在这个环境下,共用体占16个字节;

如果字符串的长度小于16,使用内部固定的字符数组存放;(使用_Buff)
如果字符串的长度大于等于16,则从堆上开辟空间存放;( 使用_Ptr)

所以vs中,string类大小占16+4+4+4=28字节.

在g++中

string类只有一个指针

堆空间
string类
size_type _M_length
size_type _M_capacity
_Atomic_word _M_refcount
存储字符串的位置
指针

在32位平台下的,string对象的大小共占4字节,引用计数_M_refcount是为写时拷贝服务的.


string类的模拟实现

看了上面的结构,是不是想动刀子的心情都有了,
但是不用担心,模拟实现没有必要完全一模一样,
我们只需要把核心的结构以及功能实现就可以了.
以下是鄙人的代码

首先我们已经了解了string类的核心成员变量:

  • 指向字符数组的指针(在堆上申请空间存储c格式字符串)
  • size_t字段(存储字符串的长度)
  • size_t字段(存储字符串的容量)
class string
{
public://方法
private:char* _arr;size_t _size;size_t _capacity;
}

这里string类方法也可以分为默认成员和迭代器和增删差改

string.h

namespace my_room
{class string{//友元函数friend ostream& operator<<(ostream& _cout, const string& s);friend istream& operator>>(istream& _cin, string& s);public://迭代器typedef char* iterator;typedef const char* const_iterator;iterator begin();const_iterator begin()const;iterator end();const_iterator end()const;public://默认成员函数string(const char* str = "");string(const string& s);string& operator=(const string& s);~string();////增删查改size_t insert(size_t pos, char c);size_t insert(size_t pos, const char* str);void push_back(char c);string& operator+=(char c);void append(const char* str);string& operator+=(const char* str);string& erase(size_t pos, size_t len);size_t find(char c, size_t pos = 0) const;size_t find(const char* s, size_t pos = 0) const;///扩容以及与属性相关的方法void resize(size_t n, char c = '\0');void reserve(size_t n);size_t size()const;size_t capacity()const;bool empty()const;char& operator[](size_t index);const char& operator[](size_t index)const;void clear();void swap(string& s);const char* c_str()const;///relational operators比较字符串大小bool operator<(const string& s);bool operator<=(const string& s);bool operator>(const string& s);bool operator>=(const string& s);bool operator==(const string& s);bool operator!=(const string& s);private:char* _str = nullptr;size_t _capacity = 0;size_t _size = 0;};
}

以下是string.cpp

首先我们把默认成员函数搞定:

namespace my_room
{string::string(const char* str)	:_str(new char[1]{0})	//如果是空字符串,需要放一个'\0'{int size = strlen(str);reserve(size);for (int i = 0; i < size; i++){_str[i] = str[i];}_size = size;}string::string(const string& s):_str(new char[1]{ 0 }){string tmp(s.c_str());	//这里拷贝构造的tmp就是我们的需要的字符串swap(tmp);		//把不需要的this指向的_str释放掉}string& string::operator=(const string& s){if (this != &s){string tmp(s.c_str());	//与拷贝构造的原理相同swap(tmp);}return *this;}string::~string(){delete[] _str;_str = nullptr;_size = _capacity = 0;}
}

注意:

用c格式空串构造字符串时,_str如果为nullptr,会有空指针解引用问题,所以应该在初始化列表中初始化一个'\0'.

接下来让我们把复用的函数给它解决掉:

namespace my_room
{void string::reserve(size_t n){if (n > capacity()){//异地扩容:开新空间,拷贝数据,释放旧空间char* tmp = new char[n + 1]{0};		//这个n和_capacity都表示有效字符串容量,所以实际多开一个for (int i = 0; i < size(); i++)	{tmp[i] = _str[i];}delete[] _str;_str = tmp;_capacity = n;}}size_t string::insert(size_t pos, char c){assert(pos <= size());	//取等于,因为可以在尾部插入if (_size + 1 > capacity()){int n = 0;n = capacity()==0 ? 4 : capacity()*2;reserve(n);}int end = size();while (end>pos)		//从后往前移动数据{_str[end] = _str[end - 1];end--;}_str[pos] = c;_size++;_str[_size] = 0;	//别忘了给字符串结束标志return pos;}size_t string::insert(size_t pos, const char* str){assert(pos <= size());int len = strlen(str);if (_size + len > capacity()){int n = 0;n = _size + len > capacity() * 2 ? _size + len : capacity() * 2;reserve(n);}int end = _size + len;while (end > pos+len-1)		//当len为1时,和上面一样的{_str[end] = _str[end - len];end--;}for (int i = 0; i < len; i++){_str[pos + i] = str[i];}_size += len;_str[_size] = 0;return pos;}// 删除pos位置后的len个元素,并返回该元素的下一个位置size_t string::erase(size_t pos, size_t len){assert(pos < size());if (pos + len >= size())	//删除pos位置以及之后的数据{len = size() - pos;}else{int begin = pos+len;while (begin < size()){_str[begin - len] = _str[begin];begin++;}}_size -= len;_str[_size] = 0;		//字符串结束标志符return pos;}
}

注意:

在insert函数中的pos的比较问题尽量不要使用等号,因为在边界0的情况下,比较无符号整形容易出现意料之外的问题.

还有一些简单的函数:

namespace my_room
{size_t string::size()const{return _size;}size_t string::capacity()const{return _capacity;}bool string::empty()const{return _size == 0;}const char* string::c_str()const{return _str;}//------------------------------------------------------------------------char& string::operator[](size_t index){return _str[index];}const char& string::operator[](size_t index)const{return _str[index];}//-------------------------------------------------------------bool string::operator<(const string& s){return strcmp(_str, s._str) < 0;}bool string::operator<=(const string& s){return !(*this > s);}bool string::operator>(const string& s){return strcmp(_str, s._str)>0;}bool string::operator>=(const string& s){return !(*this < s);}bool string::operator==(const string& s){return strcmp(_str, s._str) == 0;}bool string::operator!=(const string& s){return !(*this == s);}
//----------------------------------------------------------------------  void string::clear(){_str[0] = 0;_size = 0;}void string::swap(string& s){std::swap(_str, s._str);std::swap(_size, s._size);std::swap(_capacity, s._capacity);}
}

剩下的几乎都是代码复用:

namespace my_room
{void string::resize(size_t n, char c){reserve(n);if (n > size()){while (n > size()){push_back(c);}}else{_str[n] = '\0';_size = n;}}void string::push_back(char c){insert(size(), c);}string& string::operator+=(char c){insert(size(), c);return *this;}void string::append(const char* str){insert(size(), str);}string& string::operator+=(const char* str){insert(size(), str);return *this;}//----------------------------------------------------------------size_t string::find(char c, size_t pos) const{assert(pos < size());for (size_t i = pos; i < size(); i++){if (_str[i] == c){return i;}}return -1;}size_t string::find(const char* s, size_t pos) const	//相当于模拟strstr{assert(pos < size());size_t len = strlen(s);if (pos + len <= size()){const char* cur = _str + pos;while (*cur){const char* dest = cur;const char* src = s;while ((*dest == *src) && *src){dest++;src++;}if (*src == 0){return cur - _str;}cur++;}}return -1;}
}

还剩下个迭代器:

namespace my_room
{string::iterator string::begin(){return _str;}string::const_iterator string::begin()const{return _str;}string::iterator string::end(){return _str + _size;}string::const_iterator string::end()const{return _str + _size;}
}

小伙伴们,动起手来吧,只要稍微一动手,就发现真的是soeasy!🥰
你看鄙人都写出来了勒(写的时候不知道出了多少bug!🙂,有错请指出然后给我一句建议:还得练啊)


希望该片文章对您有帮助,请点赞支持一下吧😘💕

版权声明:

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

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