【C++】string接口使用

 hello!这里是王_哈_哈 Jw ! (C++在学中)𓆡𓆝𓆟𓆜𓆞 𓆝𓆟...

本篇主要通过C++文档学习C++的string,通过了解与使用各种接口学习string类的增删查改。(下一篇通过模拟实现string更深入理解)

一、string简介

        C语言通常用一个字符数组来进行对字符串的操作,而C++对其封装形成了string,使用起来更加方便了。

        string是C++标准库提供的一个类,用于处理和操作字符串。它封装了一个动态字符数组,同时提供了许多成员函数和操作符重载。我们可以通过在cplusplus上查看各种接口,来了解其使用。string虽然在设计和使用上具有容器的一些特征,但C++标准库并未直接归类为容器,因为他主要用于表示和操作字符串而不是任意类型的集合。

C++学习推荐网站(参考文档):

前者覆盖了整个C++标准,内容全面深入,后者侧重于解释C++标准库的用法,简明易懂。

最重要的就是看文档!!!以下几乎废话!

 

二、string的使用

 1 头文件

        使用前包含头文件

#include<string>

2 初始化

        string可以使用 构造函数 以及 operator= 进行初始化。

      2.1 文档内容

      2.2 使用示例

//构造函数初始化
	string s1;
	string s2("Hello World");
	string s3(s2);
	string s4(s2,6,5);
	string s5("123456",3);
	string s6(6,'x');
	string s7(s2.begin(),s2.end());

	initializer_list<char> ilist = { 'h','e','l','l','o' };
	string s12(ilist.begin(), ilist.end());

	//operator=
	string s8 = s2;
	string s9 = "hahahaha";
	//string s10 = 'a'; 无法通过编译 
	string s11 = s8 + s9;

          ​​2.3 注意事项

  
   ✎在构造函数的(3)中出现了npos,它是string中的静态成员常量 库中是这样定义的:static const size_t npos = -1; 它表示的是整型的最大值,在string (const string& str, size_t pos, size_t len = npos);最后的len给的是缺省值,如果没有传参数,那么默认为npos,此时函数内部处理后,直接从pos处取到字符串结束去初始化。

  ✎注意第(7),迭代区间是 [first,last) 左闭右开的。

  ✎operator的(3)可以使用单个字符初始化string,但是我在使用VS编译时,使用示例的s10无法通过,如果想用单个字符初始化string还是使用 s1(1,'c') 或 s1 = "c" 吧

  ✎文档解释的第(8)initializer list(初始化列表)是C++11中的内容,使用示例中的s12是一个简单用法。

3 string的遍历

  3.1 operator[],at

        string重载了运算符[]使它能像字符串一样访问其中的字符。此外还有at函数和[]的功能几乎一样。

   使用&区别

        它们使用起来并没有什么区别,不同的是越界检查时,operator[]是用断言报错,而at函数是抛异常

string s1("Hello world");
cout << s1[2] << endl;
cout << s1.at(2) << endl;
//最后都会输出‘l’

  3.2 迭代器

        迭代器有些类似于指针,它可以通过begin和end获取字符的第一个位置和最后一个位置的地址,然后解引用遍历/修改。

           使用
string s1("Hello world");

//通过begin和end实现正向遍历
string::iterator it1 = s1.begin();
while (it1 != s1.end())
{
	cout << *it1 << " ";
	it1++;	//指向下一个位置
}
cout << endl;

//通过rbegin和rend实现反向遍历
string::reverse_iterator it2 = s1.rbegin();
while (it2 != s1.rend())
{
	cout << *it2 << " ";
	it2++;	
}
cout << endl;

        输出结果:

        注意事项
  
   ✎迭代器不仅可以遍历访问,也可以修改内容。不是只能是s1.bengin()也可以s1.bengin()++s1.bengin() + 3...

   ✎const对象要调用const类型的迭代器const_iterator.

   ✎刚开始可以简单的理解为 typedef char* iterator; typedef const char* iterator; 也是这个原因在类外面使用时需要加域作用限定符string::),所以它们只是类型名,通常用it作其变量名,一个程序中不能有两个相同的

   ✎反向遍历string时可以使用rbegin和rend,迭代器的类型为reverse_inerator,此时迭代器也还是++往后走而不是--

   ✎结合上两条,当我们需要对const类型的string进行反向迭代时迭代器的类型为string::const_reverse_inerator,很长,这一整段可以用auto直接替代。

   ✎cbegin和cend就是const_interator,是C++11中的,提升了代码可读性,使人一眼就能看出是只读的

  3.3 范围for

        范围for在底层就是迭代器的傻瓜式替代,它的使用也很简单:(依次取s1中的值复制给ch,自动判断结束,自动++往后走)如果需要对string的内容进行修改需要使用auto&。直接char& / char作为ch的类型必然是可以的。

for (auto ch : s1)
	{
		cout << ch << " ";
	}

  4 与string大小和容量有关的操作

        string是一个类,我们可以认为他的成员变量有一个指向字符串的指针 char* str; 有一个int size; 存储字符串的大小,还有一个 int capacity; 存储它的空间大小(已分配的内存容量)。

        能对其进行查看和改变的成员函数主要有这些☟

   4.1 使用

string s1("Hello world");
cout << s1.size() << endl;
cout << s1.length() << endl;
cout << s1.capacity() << endl;
cout << s1.max_size() << endl;
cout << s1.empty() << endl;

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

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

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

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

//扩容机制测试
size_t old_capacity = s1.capacity();
for (int i = 0; i < 100; ++i)
{
	s1 += 'a';
	if (s1.capacity() != old_capacity)
	{
		cout << "Capacity changed:" << old_capacity << "->" << s1.capacity() << endl;
		old_capacity = s1.capacity();
	}
}
//15 -> 31 -> 47 -> 70 -> 105 ->157

         以上程序的运行结果如下(一些结果将会在“注意事项”中解释):

  4.2 注意事项

  
   ✎字符串的大小以'\0'为标识,但size和capacity的计算都是不包含'\0'的。所以string内部实际分配的内存空间通常会比其capacity略大一些。

   ✎在以上代码的第一部分中,capacity显示的是15,因为在vs下的stl扩容机制就是一开始就为你分配15个空间,不够了扩为31,然后每次以1.5倍倍增。

   ✎size和length都是一样的,计算字符串的长度,max_size表示的是该string对象理论可以存储的字符串长度,因编译环境而不同,而且一般是无法存下那么多的

   ✎empty是判断字符串是否为空,返回值为bool类型,返回0/1

   ✎resize是修改字符串长度的,resize有两个重载函数,可以使用s1.resize(100); s1.resize(100,'x'); 当resize后跟的数值n<size,那么size就会缩小至n,但capacity不变,当n>size时,size就会扩大至该n,如果此时capacity的值也比n小,capacity的值也会增加,n>size时如果后面没有跟字符,就用'\n'填充,跟了字符,就用该字符填充

   ✎reserve(分配空间)只会改变capacity,reserve(n)如果n>capacity,就扩容至n,capacity也变为n,但是当n < capacity时,因stl的版本而异,vs使用的PJ版本不会缩容,g++使用的SGI版本会缩容,不过相同的是它们都不会改变size的大小,不会删除string中的字符信息

   ✎shrink_to_fit是C++11的内容,有时候size和capacity相差过大,使用shrink_to_fit可以使capacity等于size

  5 string内容的修改(增、删、查、改)

        这部分主要介绍了string的增加,删除,替换,查找...几乎包含了所有增删查改。

   使用&注意事项

        其实string的使用都大差不差,只要知道它的作用,了解它的接口,忘了就看文档就可以轻松使用。所以我就简单描述一下,并写一些注意事项。

  • operator+=、append、push_back 实现的功能都是字符串,字符数组或字符的尾插功能;assign用于在对象已经存在的情况下,给对象重新赋值,他会清除对象当前的内容,并用新值替代;insert是插入,erase是清除,replace是替换其中的一些字符,swap是进行两个string的交换。c_str用于返回c风格的字符串的指针,即一个以空格字符结尾的字符数组(因为c和c++对于字符串的管理虽然相似,但仍然不同,而c++需要兼容c所以提供了这样一个接口);data返回指向字符数组的指针,这个数组表示字符串对象的内容(c++11以后与c_str返回的内容一致);get_allocator返回用于分配string对象内存的分配器对象,这通常用于自定义内存管理;copy复制字符串char str1[10]; str2.copy(str1,5); ←将str2中的前5个字符复制到str1中;find查找字符或字符串第一次出现的位置,返回下标;rfind从后往前找;find_first_of查找字符串中第一次出现任意一个给定字符,返回位置下标...; substr 返回指定的子串字符,会对对象自己的内容造成修改;compare比较两个字符串,相等返回0,大于返回正数,小于返回负数。
  • c_str返回的是地址,所以如果有s1 = "abc"; s2 = s1; s1.c_str == s2.c_str; 时,结果是false。
  • 整个c++中一共有3个swap函数,有一个是算法库中的它有两个参数,string有两个swap,是string对象的交换,其中一个就是上述swap使用时s1.swap(s2),另外一个不是sring的成员函数,有两个参数,但是内部的实现方法是与成员函数相关,是为了防止不小心使用了外部算法库中的swap函数形成不必要的拷贝造成空间浪费效率低,所以如果有人写swap(s1,s2);使用的也不是算法库中的交换。
  • 如果我们使用cin/scanf来读取一串字符会发现,遇到空格就终止了,这是因为它们默认用' '/'\n'最为分割,此时我们可以使用getline来进行读取,string str; getline(cin,str); 此时就可以以换行符来判断读取结束。

 -END- 

  • 18
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

王_哈_哈 Jw

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值