C++ string用法详解

目录

一.为什么要学习string类

1.1 C语言中的字符串

二. string类的常用操作

2.1 string类的初始化

2.2 string类常用的容量操作

2.2.1 size()

 2.2.2 length() 函数

2.2.3   capacity() 函数

2.2.4    empty()函数

 2.2.5 resize()函数和reserve()函数

 2.2.5 clear() 函数

2.3 string类对象的访问及遍历操作函数

2.3.1 []  (operator[])

 2.3.2 begin() 和 end()

  2.3.3 rbegin() 和 rend()

 2.3.4 范围for

 2.4. string类对象的修改操作

2.4.1 push_back() 函数

 2.4.2  append() 函数

  2.4.3 +=(operator+=)

 2.4.4 c_str

 2.4.5 find() + npos

  2.4.6 rfind()

 2.4.7 substr()

 2.5  常用string类非成员函数

2.5.1 operator+

2.5.2  >>和<<

2.5.3 getline

 2.5.4 relational operators()


一.为什么要学习string类

1.1 C语言中的字符串

   在C语言中,字符串是以'\0'结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数,但是这些库函数与字符串是分离开的,不太符合OOP的思想,而且底层空间需要用户自己管理,稍不留神可能还会越界访问。

  为了弥补这些C语言中的部分设计缺陷,C++研发出了string类,更好的服务于程序员。

重点:

在OJ中,有关字符串的题目基本以string类的形式出现,而且在常规工作中,为了简单、方便、快捷,基本都使用string类,很少有人去使用C库中的字符串操作函数。为了找到好Offer,熟练掌握string类是我们C艹程序员的必要工作。

二. string类的常用操作

  string类的文档链接:https://cplusplus.com/reference/string/string/

  同时,使用string类大多数情况还需要头文件#include<string>

2.1 string类的初始化

  string对象的初始化和普通类型变量的初始化基本相同,只是string作为类,还有类的一些特性:使用构造函数初始化。

  String类的常用初始化

函数名称(红色为重点)功能说明
string   s() 构造空的string类对象,即空字符串
string   s(const char* s) 用C-string来构造string类对象
string   s(size_t n, char c)string类对象中包含n个字符c
string   s(const string&s) 拷贝构造函数

如:

//常用构造函数
#include<iostream>
//用string类的话需要包含头文件#include<string>
using namespace std;
int main()
{
	string s1;
	string s2("abcdefg");
	string s3(99, 'a');
	string s4(s2);

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

代码结果为:

2.2 string类常用的容量操作

函数名称(红色为重点)功能说明
size()返回字符串有效字符长度,(有效空间)
length()返回字符串有效字符长度,(有效空间)
capacity()返回空间总大小
empty()检测字符串释放为空串,是返回true,否则返回false
clear()清空有效字符
reserve(size_t n=0)为字符串预留空间
resize(size_t n,char c)将有效字符的个数该成n个,多出的空间用字符c填充

如:

2.2.1 size()

 

//容量操作
#include<iostream>
using namespace std;

//  size()函数
int main()
{
	string s1(99, 'a');
	cout << s1.size() << endl;
	return 0;
}

代码结果为:

 

 2.2.2 length() 函数

//容量操作
#include<iostream>
using namespace std;

//length()函数
int main()
{
	string s1(99, 'a');
	cout << s1.length() << endl;
	return 0;
}

代码结果为:

 注意:
 size()与length()方法底层实现原理完全相同,引入size()的原因是为了与其他容器的接口保持一致,一般情况下基本都是用size()。(这个属于C++的早期设计缺陷)

2.2.3   capacity() 函数

//容量操作
#include<iostream>
using namespace std;

//capacity()函数
int main()
{
	string s1(10,'a');
	cout << s1.capacity() << endl;
	
	return 0;
}

代码结果为:

 根据vs 开辟空间的规则,创建string类时初始分配十五个字节的总空间,但实际上这里的有效空间为10。

我们可以用size求出s1的有效空间    如:

#include<iostream>
using namespace std;

//capacity()函数
int main()
{

	string s1(10,'a');
	cout << s1.capacity() << endl;
	cout << s1.size() << endl;`
	return 0;
}

 

2.2.4    empty()函数

//容量操作
#include<iostream>
using namespace std;

//  empty()函数
int main()
{
	string s1;
	string s2("12345");
	cout << s1.empty() << endl;
	cout << s2.empty() << endl;
	return 0;
}

代码结果为:

 2.2.5 resize()函数和reserve()函数

一.resize() 重新规划string的大小,但是注意,这里实际上规划的是有效空间的大小。

通过前边的知识,我们可以用size()求出有效空间的大小,用resize进行重新规划。

如:

//容量操作
#include<iostream>
using namespace std;

//resize()函数和reserve()函数
int main()
{
	string s1("Hello World");

	cout << s1.size() << endl;
	cout << s1.capacity() << endl;

	s1.resize(5);//通过resize把有效空间改为5

	cout << s1.size() << endl;
	cout << s1.capacity() << endl;

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

输出结果为:

这时候就分两种情况

1.缩小有效空间:

  这种情况下,容器中长度在n之外的部分会被截取掉,只保留n长度内的元素,但是容器的容量却没有改变,更不会出现扩容的状况,上段代码体现了这一点。

2.扩大有效空间:

  这种情况下,容器为了能够放的下更多的元素,会发生扩容,扩容之后,其容量会比原来大,这时候就会出现没有用过的有效空间,此时我们通过函数的第二个元素 c 进行剩余空间的初始化。

  也就是说,当扩容时,扩容的空间内存放的元素全都是第二个元素 C。如果没有指定第二个元素c,那就用string的默认初始化了,这种情况下,容器一定是分配了内存并全部发生了初始化的。

如:

//容量操作
#include<iostream>
using namespace std;

int main()
{
	string s1("Hello World");

	cout << s1 << endl;
	cout << s1.size() << endl;
	cout << s1.capacity() << endl;
	s1.resize(20, 'x');

	cout << s1 << endl;
	cout << s1.size() << endl;
	cout << s1.capacity() << endl;
	
	return 0;
}

代码结果为:

 注意:有效空间的变化可能会影响最大空间的变化,最大空间的变化也可能影响有效空间的变化。

二.reserve() 函数改变最大空间。
 

容量操作
#include<iostream>
using namespace std;

int main()
{
	string s1("Hello World");

	cout << s1.capacity() << endl;
	s1.reserve(20);

	cout << s1.capacity() << endl;
	
	return 0;
}

 代码结果为:

 注意:这里代码结果不同预想也是因为VS 的容量规则

 2.2.5 clear() 函数

容量操作
 #include<iostream>
using namespace std;

int main()
{
	string s1("Hello World");

	cout << s1.size() << endl;
	s1.clear();

	cout << s1.size() << endl;
	cout << s1.capacity() << endl;

	return 0;
}

代码结果为:

注意:clear()只是将string中有效字符清空,不改变底层空间大小。

2.3 string类对象的访问及遍历操作函数

函数名称  (重点为红色)功能说明
[]  (operator[])返回pos位置的字符,const string类对象调用
begin()获取第一个字符位置的迭代器
end()获取最后一个字符下一个位置的迭代器
rbegin()获取最后一个元素的反向迭代器
rend()获取第一个位置之前一个位置的反向迭代器
范围forC++11支持更简洁的范围for的新遍历方式

2.3.1 []  (operator[])

实际上就是数组的[],可以随机访问元素,底层是操作符重载(不讲)。

//string类对象的访问及遍历操作函数 
#include<iostream>
using namespace std;

// []
int main()
{
	string s1("abcde");
	cout << s1[0] << endl;
	cout << s1[s1.size()-1] << endl;
	cout << s1[2] << endl;
	return 0;
}

代码结果为:

 2.3.2 begin() 和 end()

//string类对象的访问及遍历操作函数 
#include<iostream>
using namespace std;

//begin()和end()
int main()
{
	string s1("12345");
	string::iterator it = s1.begin();
	while (it != s1.end())
	{
		cout << *it << endl;
		it++;
	}
	return 0;
}

代码结果为:

 两图解迭代器原理(狗头保命):

 

 

 

 C++中,迭代器就是一个类似于指针的对象,它能够用来遍历C++标准模板库容器中的部分或全部元素,每个迭代器对象代表容器中的确定的地址。

  但在string中,我们最常用的还是数组的下标访问,故不在多描述。

  2.3.3 rbegin() 和 rend()

//string类对象的访问及遍历操作函数 
#include<iostream>
using namespace std;

//rbegin()和rend()
int main()
{
	string s1("12345");
	string::reverse_iterator it = s1.rbegin();
	while (it != s1.rend())
	{
		cout << *it << endl;
		it++;
	}
	return 0;
}

结果为:

 2.3.4 范围for

//string类对象的访问及遍历操作函数 
#include<iostream>
using namespace std;


//for(auto )
int main()
{
	string s1("12345");
	for (auto it : s1)
	{
		cout << it << endl;
	}
	return 0;
}

代码结果为:

 是不是看起来很高端:

一图解范围for:

 2.4. string类对象的修改操作

函数名称功能说明
push_back(c)在字符串后尾插字符c
append(s)在字符串后追加一个字符串
+=(operator+= )在字符串后追加字符串str
c_str返回C格式字符串
find + npos从字符串pos位置开始往后找字符c,返回该字符在字符串中的位置
rfind从字符串pos位置开始往前找字符c,返回该字符在字符串中的位置
substr在str中从pos位置开始,截取n个字符,然后将其返回

2.4.1 push_back() 函数

类似于链表的尾插

//string类对象的访问及遍历操作函数 
#include<iostream>
using namespace std;

int main()
{
	string s1("Hello ");

	cout << s1 << endl;
	s1.push_back('W');
	s1.push_back('o');
	s1.push_back('r');
	s1.push_back('l');
	s1.push_back('d');

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

结果为:

 2.4.2  append() 函数

也类似于链表的尾插,但是插入的是一个字符串。

//string类对象的访问及遍历操作函数 
#include<iostream>
using namespace std;

int main()
{
	string s1("Hello ");
	cout << s1 << endl;
	s1.append("World");
	cout << s1 << endl;
	return 0;
}

结果为:

  2.4.3 +=(operator+=)

本质上是一个符号重载,依旧类似于链表的尾插。

//string类对象的访问及遍历操作函数 
#include<iostream>
using namespace std;

int main()
{
	string s1("Hello ");
	cout << s1 << endl;
	s1 += "World";
	cout << s1 << endl;
	return 0;
}

结果为:

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

 2.4.4 c_str

  在C语言中,字符串是以'\0'结尾的一些字符的集合。但在C++中,string类不以'\0'结尾,而是根据有效空间的大小结束。

  这个函数的本质作用是:将 const string* 类型 转化为 const char* 类型

 2.4.5 find() + npos

find有很多函数重载,我们只学一种就好了。

     size_t find  (const string &s,int pos=0);

s是需要查找的字符串,pos是从哪个位置查找 , 如果未查找到则返回npos(size_t 的最大值)。

如:

//string类对象的访问及遍历操作函数 
#include<iostream>
using namespace std;

int main()
{
	string s1("fghasdabc");
	cout << s1.find('a') << endl;

	string s2("abc");
	cout << s1.find(s2) << endl;
	cout << s1.find('e') << endl;
	return 0;
}

代码结果为:

  2.4.6 rfind()

同样,rfind()和find()只有一个往前找,一个像后找的区别:

size_t find  (const string &s,int pos=npos);

 

//string类对象的访问及遍历操作函数 
#include<iostream>
using namespace std;

int main()
{
	string s1("fghasdabc");
	cout << s1.rfind('a') << endl;

	string s2("abc");
	cout << s1.rfind(s2) << endl;
	cout << s1.rfind('e') << endl;
	return 0;
}

 此时 第一个打印结果就会发生变化:

 2.4.7 substr()

函数定义为: string substr(size_t pos=0,size_t len=npos) const;

作用为:在string的pos位置截取n个字符,然后返回

//string类对象的访问及遍历操作函数 
#include<iostream>
using namespace std;

int main()
{
	string s1("Hello World");

	cout << s1 << endl;
	string s2(s1.substr(0, 5));

	cout << s1 << endl;

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

结果为:

 2.5  常用string类非成员函数

函数名字 (红色为重点)作用说明
operator+尽量少用,因为传值返回,导致深拷贝效率低
operator>> 输入运算符重载
operator<< 输出运算符重载
getline 获取一行字符串
relational operators字符串大小比较

2.5.1 operator+

这个大家根据  + 和 +=的特性 ,再结合类的知识点,自己推一下为什么效率低(绝对不是因为我懒!!!)。

2.5.2  >>和<<

  重载输入输出。

2.5.3 getline

函数定义为:

istream& getline (istream & is,string& str);

注意:
cin输入会自动吃点前置换行和空格,即cin输入得到的不可能是空串。而getline不会吃掉换行符号和空格,可能会使得输入出现意料之外的错误。

比如说:

#include<iostream>
#include<string>//需要头文件
using namespace std;

int main()
{
	string s1;//输入个Hello World 看看
	cin >> s1;
	cout <<endl<< s1 << endl;
	//string s2;
	//getline(cin, s2);
	//cout << endl << s2 << endl;

	return 0;
}

代码结果为:

 可见,cin遇见空格就结束了,可能会使得输入出现意料之外的错误。

正确的做法是使用getline();

//string类对象的访问及遍历操作函数 
#include<iostream>
#include<string>//需要头文件
using namespace std;

int main()
{
	//string s1;//输入个Hello World 看看
	//cin >> s1;
	//cout <<endl<< s1 << endl;
	string s2;
	getline(cin, s2);
	cout << endl << s2 << endl;

	return 0;
}

 2.5.4 relational operators()

 

 就是符号重载了关系运算符;

使得>=,<=等运算符可以用于字符串比较

 

  • 5
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
目录 1 正文 3 一、 C++string的使用 3 1.1 C++ string简介 3 1.2 string的成员 3 1.2.1 append 3 1.2.2 assign 4 1.2.3 at 4 1.2.4 begin 5 1.2.5 c_str 5 1.2.6 capacity 5 1.2.7 clear 6 1.2.8 compare 6 1.2.9 copy 6 1.2.10 _Copy_s 6 1.2.11 data 6 1.2.12 empty 6 1.2.13 end 6 1.2.14 erase 6 1.2.15 find 6 1.2.16 find_first_not_of 7 1.2.17 find_first_of 8 1.2.18 find_last_not_of 8 1.2.19 find_last_of 8 1.2.20 get_allocator 8 1.2.21 insert 8 1.2.22 length 8 1.2.23 max_size 8 1.2.24 push_back 8 1.2.25 rbegin 8 1.2.26 rend 8 1.2.27 replace 8 1.2.28 reserve 10 1.2.29 resize 11 1.2.30 rfind 11 1.2.31 size 11 1.2.32 substr 11 1.2.33 swap 11 1.3 string的构造 11 1.4 string的重载运算符 12 1.5 string与algorithm相结合的使用 12 1.5.1 string与remove 12 1.5.2 string与unique、sort 12 1.5.3 string与search 12 1.5.4 string和find、find_if 13 1.5.5 string与copy、copy_if 13 1.5.6 string与count、count_if 14 1.6 string与wstring 14 1.6.1 简介 14 1.6.2 wstring实例 15 1.6.3 wstring与控制台 15 1.6.4 string与wstring的相互转换 16 1.7 stringC++流 21 1.7.1 C++流简介 21 1.7.2 string与iostream、fstream 21 1.8 格式化字符串 22 1.8.1 简单常用的C方法 22 1.8.2 boost的方法 22 1.9 string与CString 23 二、 boost字符串算法库 23 2.1 boost字符串算法库导论 23 2.1.1 boost.algorithm.string是什么? 23 2.1.2 相关 23 2.1.3 boost.range导论 23 2.1.4 boost.regex导论 23 2.1.5 boost.algorithm.string的DNA 24 2.2 boost字符串算法解密 24 2.2.1 修剪(trim.hpp) 24 2.2.2 转换(case_conv.hpp) 26 2.2.3 判断式、断言函数(predicate.hpp)【Predicates】 27 2.2.4 查找 28 2.2.5 删除和替换 29 2.2.6 分割和组合 31 2.2.7 其它 32 三、 C字符串 32 3.1 C字符串常用算法 32 3.1.1 strcpy wcscpy 32 3.1.2 strcat wcscat 32 3.1.3 strchr wcschr 32 3.1.4 strcmp wcscmp 33 3.1.5 stricmp wcsicmp 33 3.1.6 strlen wcslen 33 3.1.7 strlwr/_strlwr wcslwr/_wcslwr 33 3.1.8 strncat wcsncat 33 3.1.9 strcspn wcscspn 33 3.1.10 strdup/_strdup wcsdup/_wcsdup 34 3.1.11 strncpy wcsncpy 34 3.1.12 strpbrk wcspbrk 35 3.1.13 strrev/_strrev wcsrev/_wcsrev 35 3.1.14 strset/_strset/_strset_l wcsset/_wcsset/_wcsset_l 35 3.1.15 strstr/wcsstr 35 3.1.16 strtok/wcstok 36 3.1.17 strupr/_strupr wcsupr/_wcsupr 36 3.2 更安全的C字符串函数 36 3.2.1 简述 36 3.2.2 简单实例 36 3.2.3 定制 38 3.2.4 兼容 41 3.3 通用字串函数 47 3.3.1 简述 47 3.3.2 简单实例 47 3.3.3 映射表 48 3.4 API级的字符串处理 48 3.4.1 简述 48 3.4.2 旧的API 48 3.4.3 Shell字符串函数 48 3.4.4 新的安全版字符串处理API 48 四、 C++字符串使用的建议 51 附录1:参考资料: 51 附录2: MSSTL中basic_string的部分源码解读 51 2.1 string的allocator 51 2.1.1 Allocate和Deallocate 51 2.1.2 allocator的泛型实现 52 2.1.3 string与char_traits 54 2.1.4 以char和wchar_t特化char_traits 56 附录3:Boost.Format中文文档 57 2.1 大纲 57 2.2 它是如何工作的 57 2.3语法 58 2.3.1 boost::format( format-string ) % arg1 % arg2 % ... % argN 58 2.3.2 printf 格式化规则 59 2.3.3 新的格式规则 60 附录4 TCHAR.h 映射表 60

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值