CD34.【C++ Dev】STL库的string的使用 (上)

目录

1.知识回顾

2.串联类和对象的知识重新理解

构造函数

string();

string (const string& str);

string (const string& str, size_t pos, size_t len = npos);

string (const char* s);

string (size_t n, char c);

append和push_back

string& append (const string& str); 

string& append (const string& str, size_t subpos, size_t sublen);

string& append (const char* s); 

string& append (const char* s, size_t n);

template    string& append (InputIterator first, InputIterator last);

operator+=

operator[ ]

理解[ ]本质是解引用

上方代码能否访问到\0?

方法1:下条件断点后监视

方法2:反汇编后看内存,手动查找

方法3:直接监视窗口看封装好的string类的str

缺点


1.知识回顾

之前在C++ Contest专栏提到过string的使用

CC12.【C++ Cont】string类字符串的创建、输入、访问和size函数

CC13.【C++ Cont】初识string类字符串的迭代器

CC14.【C++ Cont】string类字符串的push_back、pop_back、字符串+=与+运算和insert

CC15.【C++ Cont】string类字符串的find和substr函数

CC16.【C++ Cont】string类字符串的关系运算和与string有关的函数

2.串联类和对象的知识重新理解

上方提到的文章讲的比较浅,只是介绍了怎么用,本文将用类和对象的思想来理解

https://legacy.cplusplus.com/reference/string/string/?kw=string网为线索:

构造函数

 下面只讲常用的

string();

无参数传递,即默认构造,也称无参构造

string (const string& str);

传参的类型为const string,为拷贝构造

string (const string& str, size_t pos, size_t len = npos);

传参的类型为const string,为拷贝构造,只不过是拷贝构造str的子串,显然第3个参数是缺省参数,如果不写,默认从pos位置一直截取的string风格的字符串的结尾

string (const char* s);

const char*为C语言风格的字符串类型,因此为使用C风格的字符串构造

string (size_t n, char c);

使用n个字符c来构造

append和push_back

https://legacy.cplusplus.com/reference/string/string/append/

append v.追加 即向原string类字符串后追加字符串,作用类似push_back,只不过push_back只能追加字符

有关push_back成员函数的简单使用参见CC14.【C++ Cont】string类字符串的push_back、pop_back、字符串+=与+运算和insert文章

此外:如果string的空间不够,append或push_back会自动扩容,(具体的扩容策略和编译器的处理有关,没有统一的规定),C语言strcat,不能自动扩容且找\0耗时

string& append (const string& str); 

向原string类字符串后追加string类字符串(类似push_back)

string& append (const string& str, size_t subpos, size_t sublen);

向原string类字符串后追加string类字符串str的子字符串

string& append (const char* s); 

向原string类字符串后追加C语言风格的字符串

string& append (const char* s, size_t n);

向原string类字符串后追加C语言风格的字符串的前n个字符

代码示例:

#include <iostream>
#include <string>
using namespace std;
int main()
{
	string str("teststring");
	str.append("abcdef", 3);
	cout << str << endl;
	return 0;
}

运行结果:

template <class InputIterator>
   string& append (InputIterator first, InputIterator last);

 向原string类字符串后追加范围为[first,last)的一串字符

代码示例:

#include <iostream>
#include <string>
using namespace std;
int main()
{
	string str1("teststring");
	string str2("000abc111");
	str1.append(str2.begin()+3,str2.begin()+6);
	cout << str1 << endl;
	return 0;
}

运行结果:

operator+=

参见CC14.【C++ Cont】string类字符串的push_back、pop_back、字符串+=与+运算和insert文章

operator[ ]

https://legacy.cplusplus.com/reference/string/string/operator[]/

给了两种重载形式,一个可以修改字符串,一个不能修改字符串

可做如下测试:

#include <iostream>
#include <string>
using namespace std;
int main()
{
	string str1("helloworld");
	const string str2("teststring");
	str1[1];
	str2[1];
	return 0;
}

写法等价为:使用点操作符调用成员函数

str1.operator[](1);
str2.operator[](2);

从地址上看,调用operator[]的地址不同,因此是不同的重载函数:

如果从operator[]函数的定义上来看:

str1[1]的operator[]没有有const修饰:

str2[1]的operator[]有const修饰:

理解[ ]本质是解引用

代码示例:可以像数组一样访问

#include <iostream>
#include <string>
using namespace std;
int main()
{
	string str("helloworld");
	for (size_t i = 0; i < str.size(); i++)
		cout << str[i];
	return 0;
}

运行结果:

上方代码能否访问到\0?
方法1:下条件断点后监视

监视窗口查看:

str[i]解引用后是最后一个字母d,不是\0

方法2:反汇编后看内存,手动查找

Debug+x86环境下,for循环的反汇编代码:

发现ebp-3Ch和ebp-30h高频出现,由mov dword ptr [ebp-3Ch],0 猜测这是为变量i赋初值,因此[ebp-3Ch]存的是i的值, 由cmp dword ptr [ebp-3Ch],eaxjae 00540BDD猜测这是i < str.size()的条件判断,因此猜测eax临时存储的是str.size的值,可以看看寄存器:

0x0000000A=十进制的10,不带\0的helloworld恰好占10个字节,因此不会访问到\0

方法3:直接监视窗口看封装好的string类的str

备注:如果想强制打印\0可以将i < str.size()改成i <= str.size()

循环后再打印一个#检测\0有没有占位:

#include <iostream>
#include <string>
using namespace std;
int main()
{
	string str("helloworld");
	for (size_t i = 0; i <= str.size(); i++)
		cout << str[i];
	cout << "#";
	return 0;
}

Visual Studio 2022查看控制台窗口:

发现\0不显示,且不占位,因为VS认为str[i]超出界限,因此没有为\0占位

Dev C++查看控制台窗口:

发现\0不显示,且占位

Ubuntu Linux g++运行结果:

发现\0不显示,且不占位

发现不同平台的处理方法不同

缺点

Operator[ ]只有连续的空间才能使用,即非线性结构不能使用[ ]访问,但一些线性结构和非线性结构都可以使用迭代器访问,例如链表:

#include <iostream>
#include <string>
#include <list>
using namespace std;
int main()
{ 
	list<int> ls;
	ls.push_back(1);
	ls.push_back(3);
	ls.push_back(13);
	ls.push_back(0);
	ls.push_back(43);
	ls.push_back(546);
	ls.push_back(9);
	for (auto i = ls.begin(); i != ls.end(); i++)
	{
		cout << *i << "-->";
	}
	cout << "NULL";
	return 0;
}

运行结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

zhangcoder

赠人玫瑰手有余香,感谢支持~

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

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

打赏作者

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

抵扣说明:

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

余额充值