【一起来学C++】————(10)STL之string容器

本文详细介绍了C++中的string容器,包括其作为类的特性、构造函数、容量操作、赋值方法、字符存取、查找与替换、子串操作、插入与删除,并给出了模拟实现的简单示例,展示了string在内存管理和操作上的便利性。
摘要由CSDN通过智能技术生成

1、string基本概念

本质:

string是C++风格的字符串,而string本质上是一个类

string和char * 区别:

  • char * 是一个指针
  • string是一个类,类内部封装了char*,管理这个字符串,是一个char*型的容器。

特点:
string 类内部封装了很多成员方法
例如:查找find,拷贝copy,删除delete 替换replace,插入insert
string管理char*所分配的内存,不用担心复制越界和取值越界等,由类内部进行负责

2、string构造函数

在这里插入图片描述

#include <iostream>
using namespace std;
#include <string>
//string构造
void test01()
{
	string s1; //创建空字符串,调用无参构造函数
	cout << "str1 = " << s1 << endl;
	const char* str = "hello world";
	string s2(str); //把c_string转换成了string
	cout << "str2 = " << s2 << endl;
	string s3(s2); //调用拷贝构造函数
	cout << "str3 = " << s3 << endl;
	string s4(10, 'a');
	cout << "str3 = " << s3 << endl;
}

int main() {
	test01();
	system("pause");
	return 0;
}

总结:

在使用string类时,必须包含#include头文件以及using namespace std;

3、string类对象的容量操作

在这里插入图片描述

// size/clear/resize
void Teststring1()
{
	// 注意:string类对象支持直接用cin和cout进行输入和输出
	string s("hello, bit!!!");
	cout << s.size() << endl;
	cout << s.length() << endl;
	cout << s.capacity() << endl;
	cout << s <<endl;
	// 将s中的字符串清空,注意清空时只是将size清0,不改变底层空间的大小
	s.clear();
	cout << s.size() << endl;
	cout << s.capacity() << endl;
	// 将s中有效字符个数增加到10个,多出位置用'a'进行填充
	// “aaaaaaaaaa”
	s.resize(10, 'a');
	cout << s.size() << endl;
	cout << s.capacity() << endl;
	// 将s中有效字符个数增加到15个,多出位置用缺省值'\0'进行填充
	// "aaaaaaaaaa\0\0\0\0\0"
	// 注意此时s中有效字符个数已经增加到15个
	s.resize(15);
	cout << s.size() << endl;
	cout << s.capacity() << endl;
	cout << s << endl;
	// 将s中有效字符个数缩小到5个
	s.resize(5);
	cout << s.size() << endl;
	cout << s.capacity() << endl;
	cout << s << endl;
}

//================================================================================

void Teststring2()
{
	string s;
	// 测试reserve是否会改变string中有效元素个数
	s.reserve(100);
	cout << s.size() << endl;
	cout << s.capacity() << endl;
	// 测试reserve参数小于string的底层空间大小时,是否会将空间缩小
	s.reserve(50);
	cout << s.size() << endl;
	cout << s.capacity() << endl;
}

// 利用reserve提高插入数据的效率,避免增容带来的开销
//================================================================================

void TestPushBack()
{
	string s;
	
	size_t sz = s.capacity();
	cout << "making s grow:\n";
	for (int i = 0; i < 100; ++i)
	{
		s.push_back('c');
		if (sz != s.capacity())
		{
			sz = s.capacity();
			cout << "capacity changed: " << sz << '\n';
		}
	}
}
void TestPushBackReserve()
{
	string s;
	s.reserve(100);
	size_t sz = s.capacity();
	cout << "making s grow:\n";
	for (int i = 0; i < 100; ++i)
	{
		s.push_back('c');
		if (sz != s.capacity())
		{
			sz = s.capacity();
			cout << "capacity changed: " << sz << '\n';
		}
	}
}

注意:

  1. size()与length()方法底层实现原理完全相同,引入size()的原因是为了与其他容器的接口保持一致,一般情况下基本都是用size()。
  2. clear()只是将string中有效字符清空,不改变底层空间大小
  3. resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不同的是当字符个数增多时:resize(n)用0填充多出的元素空间,resize(size_t n, char c)用字符c来填充多出的元素空间。注意:resize在改变元素个数时,如果是将元素个数增多,可能会改变底层容量的大小,如果是将元素个数减少,底层空间总大小不变。
  4. reserve(size_t res_arg=0):为string预留空间,不改变有效元素个数,cpp 当reserve的参数小于string的底层空间总大小时,reserver不会改变容量大小。

4、 string赋值操作

string& operator=(const char* s);          //char*类型字符串 赋值给当前的字符串
string& operator=(const string &s);		 //把字符串s赋给当前的字符串
string& operator=(char c); 			//字符赋值给当前的字符串
string& assign(const char *s); 			//把字符串s赋给当前的字符串
string& assign(const char *s, int n); 			//把字符串s的前n个字符赋给当前的字符串
string& assign(const string &s);			 //把字符串s赋给当前字符串
string& assign(int n, char c); 		//用n个字符c赋给当前字符串
//赋值
void test01()
{
	string str1;
	str1 = "hello world";
	cout << "str1 = " << str1 << endl;
	string str2;
	str2 = str1;
	cout << "str2 = " << str2 << endl;
	string str3;
	str3 = 'a';
	cout << "str3 = " << str3 << endl;
	string str4;
	str4.assign("hello c++");
	cout << "str4 = " << str4 << endl;
	string str5;
	str5.assign("hello c++",5);
	cout << "str5 = " << str5 << endl;
	string str6;
	str6.assign(str5);
	cout << "str6 = " << str6 << endl;
	string str7;
	str7.assign(5, 'x');
	cout << "str7 = " << str7 << endl;
}
int main() {
	test01();
	system("pause");
	return 0;
}

5、string类对象的访问及遍历操作

在这里插入图片描述

string字符存取

string中单个字符存取方式有两种

char& operator[](int n); //通过[]方式取字符
char& at(int n); //通过at方法获取字符

示例:

void test01()
{
	string str = "hello world";
	for (int i = 0; i < str.size(); i++)
	{
		cout << str[i] << " ";
	}
	cout << endl;
	for (int i = 0; i < str.size(); i++)
	{
		cout << str.at(i) << " ";
	}
	cout << endl;
	//字符修改
	str[0] = 'x';
	str.at(1) = 'x';
	cout << str << endl;
}
int main() 
{
	test01();
	system("pause");
	return 0;
}

6、string查找和替换

在这里插入图片描述

//查找和替换
void test01()
{
	//查找
	string str1 = "abcdefgde";
	int pos = str1.find("de");
	if (pos == -1)
	{
		cout << "未找到" << endl;
	}
	else
	{
		cout << "pos = " << pos << endl;
	}
	pos = str1.rfind("de");
	cout << "pos = " << pos << endl;
	}
void test02()
{
	//替换
	string str1 = "abcdefgde";//字符串从0开始
	str1.replace(1, 3, "1111");
	cout << "str1 = " << str1 << endl;
}
int main() {
	//test01();
	//test02();
	system("pause");
	return 0;
}

总结:

  • find查找是从左往后,rfind从右往左
  • find找到字符串后返回查找的第一个字符位置,找不到返回-1
  • replace在替换时,要指定从哪个位置起,多少个字符,替换成什么样的字符串
    在这里插入图片描述

7、string子串

在这里插入图片描述

//子串
void test01()
{
	string str = "abcdefg";
	string subStr = str.substr(1, 3);
	cout << "subStr = " << subStr << endl;
	string email = "hello@sina.com";
	int pos = email.find("@");
	string username = email.substr(0, pos);
	cout << "username: " << username << endl;
}
int main() {
	test01();
	system("pause");
	return 0;
}
void Teststring()
{
	string str;
	str.push_back(' '); // 在str后插入空格
	str.append("hello"); // 在str后追加一个字符"hello"
	str += 'b'; // 在str后追加一个字符'b'
	str += "it"; // 在str后追加一个字符串"it"
	cout<<str<<endl;
	cout<<str.c_str()<<endl; // 以C语言的方式打印字符串
	// 获取file的后缀
	string file1("string.cpp");
	size_t pos = file.rfind('.');
	string suffix(file.substr(pos, file.size()-pos));
	cout << suffix << endl;
	// npos是string里面的一个静态成员变量
	// static const size_t npos = -1;
	// 取出url中的域名
	sring url("http://www.cplusplus.com/reference/string/string/find/");
	cout << url << endl;
	size_t start = url.find("://");
	if (start == string::npos)
	{
		cout << "invalid url" << endl;
		return;
	}
	start += 3;
	size_t finish = url.find('/', start);
	string address = url.substr(start, finish - start);
	cout << address << endl;
	// 删除url的协议前缀
	pos = url.find("://");
	url.erase(0, pos+3);
	cout<<url<<endl;
}

8、string插入和删除

在这里插入图片描述

//字符串插入和删除
void test01()
{
	string str = "hello";
	str.insert(1, "111");
	cout << str << endl;
	str.erase(1, 3); //从1号位置开始3个字符
	cout << str << endl;
}
int main() {
	test01();
	system("pause");
	return 0;
}

总结:

  • 插入和删除的起始下标都是从0开始

9、string类的模拟实现

class string
{
public:
	string(const char* str = "")
	{
	// 构造string类对象时,如果传递nullptr指针,认为程序非法,此处断言下
	if(nullptr == str)
	{
		assert(false);
		return;
	}
	_str = new char[strlen(str) + 1];
	strcpy(_str, str);
	}
	
	string(const string& s): _str(new char[strlen(s._str)+1])
	{
		strcpy(_str, s._str);
	}
	
	string& operator=(const string& s)
	{
		if(this != &s)
		{
			char* pStr = new char[strlen(s._str) + 1];
			strcpy(pStr, s._str);
			delete[] _str;
			_str = pStr;
		}
		return *this;
	}
	~string()
	{
		if(_str)
		{
			delete[] _str;
			_str = nullptr;
		}
	}
private:
	char* _str;
};

在这里插入图片描述

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值