C++_STL---string类

前言

说起string类,首先需要了解的是 - string类是什么?

std::string是类模板std::basic_string的一个元素类型为char的实例化,而basic_string则是对元素指针的封装。由于basic_string的实现对字符串操作进行了优化,所以它不能用来表示除char以外的对象串。但是使用string类也避免了和'\0'的纠缠不休,也就是说,string并不关心它所代表的字符串有无'\0'作为字符串的结束标志,相反'\0'是它的一个合法元素。

string类的接口与常规容器的接口基本相同,但在此基础上也添加了一些专门用来操作string的常规接口。在使用string类时,必须包含#include头文件以及using namespace std;另外,想要更加深入的了解string类,请点击string类的文档介绍~~

string类的常用接口

因为string类的接口特别多(106个接口函数),所以这里只介绍几个常用且重要的接口。

1.string类对象的常见构造

函数说明功能说明代码演示
string()构造空的string类对象,即空字符串string s1;
string(const char* str)用C-string来构造string类对象string s2("hello");
string(const char& str)拷贝构造函数string s3(s2);

2.string类对象的容量操作

函数名称功能说明函数原型
reserve为字符串预留空间void reserve(size_t n = 0);
resize将有效字符个数改成n个,多出的空间用char c填充

void resize(size_t n);

void resize(size_t n, char c);

clear清空有效字符void clear();

特别说明:

  • 使用reserve扩容时,只会影响capacity,并不会影响size;默认不会缩容
  • 使用resize扩容,不仅会影响capacity,也会影响size,并且会将开出的空间初始化为'\0'(不显示写char c的时候);缩容的时候只会影响size

3. string类对象的访问及遍历操作

函数名称功能说明函数原型
operator[]返回pos位置的字符char& operator[] (size_t pos);
begin + end

begin获取一个字符的迭代器 

end获取最后一个字符下一个位置的迭代器

iterator begin();

iterator end();

4. string类对象的修改操作

函数名称功能说明函数原型
operator+=在字符串后追加字符串str

string& operator+= (char c);

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

c_str返回指向C格式字符串的指针const char* c_str() const;
find

从字符串pos位置开始往后找字符c,

返回该字符在字符串中的位置

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

特别说明:

  • 在string尾部追加字符时,s.push_back(c) / s.append(1, c) / s += 'c'三种的实现方式差不多,一般情况下string类的+=操作用的比较多,因为+=操作不仅可以连接单个字符,还可以连接字符串

5. string类非成员函数

函数名称功能说明函数原型
operator>>输入运算符重载istream& operator>> (istream& is, string& str);
operator<<输出运算符重载ostream& operator<< (ostream& os, const string& str);
getline获取一行字符串istream& getline (istream& is, string& str);

 特别说明:

  •         getline –> 获取一行数据(包括空格),cin不能获取空格,遇到空格就结束

vs和g++下string结构的说明

vs下string的结构

union _Bxty
{   // storage for small buffer or pointer to larger one
    value_type _buff[_BUF_SIZE];
    pointer _Ptr;
    char _Alias[_BUF_SIZE]; // to permit aliasing
} _Bx;

 string在vs下总共占28个字节,内部结构稍微复杂一点,先是有一个联合体,联合体用来定义string中字符串的存储空间:其实当size()的长度小于_buff的长度时,会优先存储在buff里面;当size()的长度大于_buff的长度时,才会存储在堆上新开辟的空间(扩容)里面。

这种设计也是有一定道理的,大多数情况下字符串的长度都小于16,那string对象创建好之后,内部已经有了16个字符数组的固定空间,不需要通过堆创建空间,效率高。


g++下string的结构

struct _Rep_base
{
    size_t       _M_size;
    size_t       _M_capacity;
    _Atomic_word _M_refcount;
}

 g++下,string是通过写时拷贝实现的,string对象总共占4个字节,内部只包含了一个指针,该指针将来指向一块堆空间,内部包含了如下字段:

  • 空间总大小
  • 字符串有效长度
  • 引用计数
  • 指向堆空间的指针,用来存储字符串

string类的模拟实现

与常用接口类似,这里只实现一些常用的

1.string类的默认成员函数

//构造函数
string(const char* str = "")     //字符串后面默认有一个\0,所以这里缺省值不需要 \0
	: _size(strlen(str))
{
	_str = new char[_size + 1];
	_capacity = _size;

	strcpy(_str, str);
}
//拷贝构造
//传统写法
string(const string& s)
{
	char* tmp = new char[s._capacity + 1];
	strcpy(tmp, s._str);
	_str = tmp;
	_size = s._size;
	_capacity = s._capacity;
}

//现代写法
string(const string& s)
{
	string tmp(s._str);        //调用构造
	swap(tmp);                 //std::swap(tmp._str, _str);std::swap(tmp._size, _size);std::swap(tmp._capacity, _capacity);
}
//赋值重载
//传统写法
string& operator=(const string& s)
{
	if (this != &s)            //防止出现自己给自己赋值的情况
	{
	    char* tmp = new char[s._capacity + 1];
		strcpy(tmp, s._str);
		delete[] _str;
		_str = tmp;
		_size = s._size;
		_capacity = s._capacity;
	}
	return *this;
}
//现代写法1
string& operator=(const string& s)
{
	if (this != &s)
	{
		string tmp(s._str);   //调用构造
		swap(tmp);            //std::swap(tmp._str, _str);std::swap(tmp._size, _size);std::swap(tmp._capacity, _capacity);
	}
	return *this;
}
//现代写法2
string& operator=(string tmp)
{
	swap(tmp);                //调用拷贝构造
	return *this;
}

 2string类对象的修改相关函数

//查找一个字符串里是否有相应的字符
size_t find(char ch, size_t pos = 0)
{
	assert(pos < _size);
	for (int i = pos; i < _size; i++)
	{
		if (_str[i] == ch)
		{
			return i;
		}
	}
	return npos;
}
//查找一个字符串里是否有相应的子串
size_t find(const char* sub, size_t pos = 0)
{
	assert(pos < _size);
	char* ptr = strstr(_str + pos, sub);

	return ptr - _str;
}
//查找子串
string substr(size_t pos = 0, size_t len = npos)
{
	assert(pos < _size);
	if (len > _size - pos)
	{
		string sub(_str + pos);        //构造一个子串
		return sub;
	}
	else
	{
		string sub;
		sub.reserve(len);              //为构造的子串开空间
		for (int i = 0; i < len; i++)
		{
			sub += _str[pos + i];      //尾插
		}
		return sub;
	}
}

 3.string类非成员函数

//流提取
ostream& operator<<(ostream& os, string& str)
{
	for (size_t i = 0; i < str.size(); i++)
	{
		os << str[i];
	}
	return os;
}
//流插入
istream& operator>>(istream& is, string& str)
{
	str.clear();        //清空有效数据

	char buff[128];     //开一个char类型的最大数组
	int i = 0;
	char ch = is.get();
	while (ch != ' ' && ch != '\n')
	{
		buff[i++] = ch; //读到的数据放到数组buff里
		if (i == 127)    
		{
			buff[i] = '\0';
			str += buff;//
			i = 0;
		}
		ch = is.get();
	}
	if (i != 0)
	{
		buff[i] = '\0';
		str += buff;
	}
	return is;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

C

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值