学习->C++篇六:string类---上篇

目录

C++中如何操作字符串?

什么是string?

使用string

常用构造函数

长度和容量相关的函数

访问string类对象中的字符

方式一:用下标的方式

方式二:用迭代器(string的迭代器底层是指针)

方式三:范围for(C++11)

vs2022下的string结构和范围for原理

 对string对象的修改操作函数

非成员函数


C++中如何操作字符串?

在C中常用字符数组表示字符串,使用#include<string.h>中的库函数来操作字符串,字符串的底层空间要自己管理,还需留意\0的位置,防止越界访问等。在C++中面向对象的思想封装了一个类string来管理字符串,用string类更方便,无需管理string的底层空间,还提供了一系列成员函数和运算符重载来操作字符串,使操作更简单、快捷,开发效率更高。

什么是string?

标准库类型string表示可变长的字符序列,本质上string是类模板basic_string实例化,用于存放char类型:


注意,这个类独立于所使用的编码来处理字节:如果用来处理多字节或变长字符(如UTF-8)的序列,这个类的所有成员(如长度或大小)以及它的迭代器,将仍然按照字节(而不是实际编码的字符)来操作,故不能用string操作多字节或者变长字符的序列,应当用basic_string的其他实例。

使用string

使用string须包含其头文件,string定义在命名空间std中,使用时可以如此:

#include<string>

using std::string;

常用构造函数

使用示例:(注:string重载了<<操作符,可以用其输出字符串内容)

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<string>

using std::string;
using std::cout;
using std::endl;

int main() 
{
	string s1;//默认构造的是空串
	string s2("hello string");
	string s3(s2);

	cout << s1 << endl;
	cout << s2 << endl;
	cout << s3 << endl;
	return 0;
}

输出:

长度和容量相关的函数

函数原型                                    函数名:函数作用     

size_t size() const;                     size/length :返回字符串的长度

void resize(size_t n,char c)        resize:修改字符串的长度为n,变长就用c填充

size_t capacity() const;              capacity:返回已分配的空间的容量

void reserve (size_t n = 0);        reserve:为字符串预留空间(可用于减少频繁扩容)

void clear();                               clear:清空字符(改变长度=0,不改变容量)

bool empty() const;                   empty:字符串是空串则返回true,否则返回false

使用示例:

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<string>

using std::string;
using std::cout;
using std::endl;

int main() 
{
	string s("hello string");
	cout << s << endl;
	//size
	cout << s.size() << endl;
	//resize
	s.resize(5);
	cout << s << endl;
	s.resize(10, 'x');
	cout << s << endl;
	//capacity,reserve
	cout << s.capacity() << endl;
	s.reserve(20);
	cout << s.capacity() << endl;
	//clear
	s.clear();
	cout << s << endl;
	//empty
	if (s.empty())
		cout << "s is empty" << endl;

	return 0;
}

输出:(注意:因为底层实现string时考虑了内存对齐等,故开辟的空间可能不是reserve准确的空间)

访问string类对象中的字符

方式一:用下标的方式

因为string支持了[]的运算符重载,也可用at成员函数访问字符,区别是后者在越界时会抛异常。

函数原型:(每个函数提供了其const版本,用于支持const对象)
char& operator[] (size_t pos);
const char& operator[] (size_t pos) const;

char& at (size_t pos);
const char& at (size_t pos) const;

方式二:用迭代器(string的迭代器底层是指针)

可将迭代器当成字符指针理解,begin返回的是首字符的迭代器,end返回的是最后一个字符的后一个位置的迭代器。

函数原型:
iterator begin();
const_iterator begin() const;
iterator end();
const_iterator end() const;

方式三:范围for(C++11)

范围for的底层是转化为迭代器去访问元素的。

 使用示例:

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<string>

using std::string;
using std::cout;
using std::endl;

int main() 
{
	string s("welcome to string");
	//一:下标访问
	for (int i = 0; i < s.size(); i++)
		cout << s[i];
	cout << endl;
	//二:迭代器访问
	string::iterator it = s.begin();//取string类域中的iterator
	while (it != s.end())
		cout << *it++ << " ";
	cout << endl;
	//三:范围for
	for (auto &e : s)//用引用可以修改字符串中的元素
		cout << ++e ;
	cout << endl;
	return 0;
}

输出:

vs2022下的string结构和范围for原理

 vs下string的结构较为复杂:

用联合体存储字符数组或字符指针:

当字符串长度较小时,使用内部固定的字符数组_Buf[]来存放字符串
当字符串长度较大时时,从堆上开辟空间,用_Ptr指针指向字符串首字符

监视窗口中可见:用_Mysize存储长度size,用_Myres存储容量capacity

了解了其结构后,再去观察范围for的反汇编代码,是否底层是迭代器呢?

可见调用了两个函数,_Unchecked_begin()和_Unchecked_end(),猜测和begin()、end()相似。

 查看其函数定义,结合上面结构体的定义可知,_Unchecked_begin()返回的是字符串首字符的指针,可见范围for的本质是指针(也就是迭代器)。

可见当存储长度较小字符串时返回_Buf,反之返回_Ptr

 判断字符串存储在_Buf还是堆区的函数

 返回指针的函数

 对string对象的修改操作函数

 高频使用函数:

void push_back (char c); 尾插一个字符c

 append/operator += 函数:在字符串后追加字符串

const char* c_str() const; 返回c格式的字符串

 注:string类中定义了变量npos表示size_t类型的最大值

size_t find (const string& str, size_t pos = 0) const;从字符串pos位置开始往后找字符c,返回该字符在字符串中的位置,没找到则返回npos

size_t rfind (const string& str, size_t pos = npos) const;从字符串pos位置开始往前找字符c,返回该字符在字符串中的位置,没找到则返回npos

string substr (size_t pos = 0, size_t len = npos) const;在str中从pos位置开始,截取len个字符构造string对象,然后返回

使用示例:

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<string>

using std::string;
using std::cout;
using std::endl;

int main() 
{
	string s1("hello string");
	string s2("hello world");
	//push_back
	s1.push_back('x');
	s1.push_back('y');
	s1.push_back('z');
	cout << s1 << endl << endl;
	//append
	s1.append(s2);
	cout << s1 << endl;
	s1.append("!!!");
	cout << s1 << endl << endl;
	//+=
	s1 += s2;
	cout << s1 << endl;
	s1 += "!!!";
	cout << s1 << endl << endl;
	//c_str
	printf("%s\n", s1.c_str());
	printf("%s\n\n",s2.c_str());
	//find
	int pos = s1.find('x');
	if (pos != string::npos)
		cout << s1[pos] << endl<<endl;
	//substr
	cout << s1.substr(6, 6) << endl;
	return 0;
}

输出:

非成员函数

 operator+传值返回两个string对象合并后的string对象,效率较低

 relationnal operators是重载了==,<,>等比较运算符,比较的是字符的ASCII码,与strcmp类似来比较两个字符串大小。

void swap (string& x, string& y);交换函数,重载了std的swap函数,效率更高,因为底层实现是交换两个string对象内部的字符指针。

operator>>运算符重载,输入字符串到string对象中,遇到空格或换行就停止。

operator<<运算符重载,输出string对象中字符串的内容。

istream& getline (istream& is, string& str);输入字符串到string对象中,遇到空格不停止,遇到换行才停止。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值