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


    1、string基本概念

    本质:

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

    string和char * 区别:

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

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

    2、string构造函数

    在这里插入图片描述

    #include 
    using namespace std;
    #include 
    //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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    总结:

    在使用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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82

    注意:

    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赋给当前字符串
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    //赋值
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

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

    在这里插入图片描述

    string字符存取

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

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

    示例:

    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    总结:

    • 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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    总结:

    • 插入和删除的起始下标都是从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;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    在这里插入图片描述

    在这里插入图片描述

  • 相关阅读:
    List接口与实现类
    HTTPS请求阶段图解分析
    【云原生&微服务十三】SpringCloud之深度源码剖析OpenFeign如何扫描所有的FeignClient
    nginx 虚拟主机的配置
    Linux系统的特点有哪些
    vue3 父组件使用ref获取获取子组件的属性方法
    2022 China Collegiate Programming Contest (CCPC) Weihai Site A J
    mac怎么设置锁屏壁纸,锁屏壁纸和屏幕壁纸不同
    最新数据挖掘赛事方案梳理!
    docker存储卷
  • 原文地址:https://blog.csdn.net/qq_38364548/article/details/126395903