【c++】string类 (一)

prettyxian 2024-10-17 12:35:02 阅读 93

简介

由于c++的历史包袱,c++要兼容c语言,c++的字符串要兼容c语言,在 C++ 中,字符串通常使用两种主要的方式来表示:

C风格字符串(C-style strings)

依然是以 <code>'\0' 结尾的字符数组。这种表示方式与 C 语言中的字符串相同。例如:

const char* str = "Hello, World!"; 在内存中,它是一个字符数组,最后一个字符是空字符 '\0'

C++ 的标准库字符串(std::string

C++ 提供了一个 std::string 类型,属于标准库的一部分。它管理自己的内存,并且不需要手动处理 '\0'。使用 std::string 更加方便和安全。例如:

#include <string>

std::string str = "Hello, World!"; std::string 处理字符串的长度、内存分配和释放,因此开发者可以专注于字符串的内容,而不必担心细节。

c风格类型的字符串我们都已经很熟悉,\0的存在让我们在处理在处理字符串的时候需要时刻小心,在手动拼接或复制字符串时经常会因为\0处理不妥而出错。c++为我们提供了一个全新的string来处理字符串的长度、内存分配和释放,因此开发者可以专注于字符串的内容,而不必担心细节。

在一切开始之前,我们先介绍一个网站。

www.cplusplus.com是一个广受欢迎的C++编程语言资源网站,成立于2000年代初期。开始由一个c++爱好者建立,后来各路大佬汇聚,网站内容也非常成熟,可供我们学习和参考。

string类的常用接口说明

构造函数 

c++98就为我们提供了7个构造函数,当然并不要求也没有必要对所有的函数烂熟于心,大多数时候把这个当成词典来使用就可以了,选常用的一部分学习。

学习类和对象很容易大家就能知道上面哪是重要的 

不传参的默认构造,拷贝构造和第四个用常量字符串初始化的构造。

<code>#define _CRT_SECURE_NO_WARNINGS 1

#include <iostream>

#include <string>

using namespace std;

int main()

{

string s1;//默认构造

string s2("123456789");

string s3(s2);//拷贝构造

cout << s1 << endl;

cout << s2 << endl;

cout << s3 << endl;

cin >> s1;

cout << s1 << endl;

return 0;

}

我们也可以向里面输入中文

便利string的三种方式

operator[]

string类重载了[],这让我们可以像数组一样访问字符串。

同时注意看,重载后返回的类型是引用,不仅可以减少拷贝,关键在于这样我们能够直接通过下标对字符串进行修改。在重载的时候加入了断言,当pos大于size(越界时),编译器会报错。  

<code>#define _CRT_SECURE_NO_WARNINGS 1

#include <iostream>

#include <string>

using namespace std;

int main()

{

string s1;

string s2("123456789");

string s3(s2);

cout << s1 << endl;

cout << s2 << endl;

cout << s3 << endl;

cout << s2[2] << endl;//可以通过下标访问

s2[0] = '5';//也可以直接修改

cout << s2 << endl;

/*cin >> s1;

cout << s1 << endl;*/

return 0;

}

遍历string的第一种方法就是:下标 + []

<code>

#include <iostream>

#include <string>

using namespace std;

int main()

{

string s1;

string s2("123456789");

string s3(s2);

cout << s1 << endl;

cout << s2 << endl;

cout << s3 << endl;

cout << s2[2] << endl;//可以通过下标访问

s2[0] = '5';//也可以直接修改

cout << s2 << endl;

/*cin >> s1;

cout << s1 << endl;*/

for (size_t i = 0; i < s2.size(); i++)

{

cout << s2[i] << " ";

}

cout << endl;

return 0;

}

迭代器 

迭代器是一种用于遍历容器(如数组、向量、链表等)元素的对象。它提供了一种统一的方法来访问不同类型的容器中的元素(所有的容器都可以由它访问),而无需了解容器的内部结构。

正向迭代器 

begin()返回第一个位置;

end()返回最后一个位置的下一个位置。

<code>for (size_t i = 0; i < s2.size(); i++)

{

cout << s2[i] << " ";

}

cout << endl;

string::iterator it= s2.begin();

while (it != s2.end())

{

cout << *it << " ";

++it;

}

cout << endl;

反向迭代器

反向迭代器提供了一个rbegin()指向最后一个位置

 

rend()指向第一个位置的前一个位置。这里任然要使用++,++被重载了让它能倒着遍历。 

<code>string s1;

string s2("123456789");

string s3(s2);

cout << s1 << endl;

cout << s2 << endl;

cout << s3 << endl;

string::reverse_iterator it = s2.rbegin();

while (it != s2.rend())

{

cout << *it << " ";

++it;

}

cout << endl;

const迭代器

由于权限,普通迭代器可读可写,无法访问const对象,const对象要用const迭代器,只读不写。 

<code>

const string s2("hello world!");

//正向

string::const_iterator cit = s2.begin();

while (cit != s2.end())

{

cout << *cit << " ";

++cit;

}

cout << endl;

//反向

string::const_reverse_iterator rcit = s2.rbegin();

while (rcit != s2.rend())

{

cout << *rcit << " ";

++rcit;

}

cout << endl;

 

 范围for

字符赋值,自动迭代,自动判断结束,底层由迭代器实现。适用于容器和数组。

<code>for (size_t i = 0; i < s2.size(); i++)

{

cout << s2[i] << " ";

}

cout << endl;

string::iterator it= s2.begin();

while (it != s2.end())

{

cout << *it << " ";

++it;

}

cout << endl;

for (auto ch : s2)

{

cout << ch << " ";

}

cout << endl;

但是由于范围for()是给ch这个局部变量赋值,并不能直接改变s2,而迭代器是直接可以改变s2的。

<code>string::iterator it = s2.begin();

while (it != s2.end())

{

*it += 2;

cout << *it << " ";

++it;

}

cout << endl;

for (auto ch : s2)

{

ch -= 2;

cout << ch << " ";

}

cout << endl;

cout << s2 << endl;

 

如果要使用范围for()来改变传入的形参,在传入时加上引用,这样就不会生成拷贝而是直接修改传入的形参。 

capacity

 不同编译器对内存空间的处理是不一样的

<code>string s;

size_t sz = s.capacity();

cout << "original capacity:" << sz << endl;

for (int i = 0; i < 100; i++)

{

s.push_back('c');

if (sz != s.capacity())

{

sz = s.capacity();

cout << "capacity changed: " << sz << endl;

}

}

在vs中有一个buff数组,该开始中string中的数据是储存在buff中的,当要储存的数据空间大于15时才会额外开空间,该开始要把buff中的数据拷贝出来一共开了两倍空间,后边都是开的1.5倍空间。c++只规定了开空间,但是怎么开空间没有做具体的要求。其他的编译器开空间的方式可能会不同。 

频繁的扩容会导致效率低下,为解决这一问题,c++提供了reserve()可以预留空间。

<code>string s("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");

cout << s.size() << endl;

cout << s.capacity() << endl << endl;

s.reserve(10);

cout << s.size() << endl;

cout << s.capacity() << endl << endl;

s.reserve(30);

cout << s.size() << endl;

cout << s.capacity() << endl << endl;

s.reserve(40);

cout << s.size() << endl;

cout << s.capacity() << endl << endl;

s.reserve(50);

cout << s.size() << endl;

cout << s.capacity() << endl << endl;

 但是c++标准并没有规定具体怎么处理空间,不同的编译器也不一样。

仅仅反转字母

 https://leetcode.cn/problems/reverse-only-letters/

题目解析:

题目中让我们仅仅反转字母,首先我们要分类-----字母和非字母;很简单所有的字母并不多,我们只需要筛选出字母就好,写一个函数实现这个功能 。要实现反转首先就要有两个位置,使用双指针,从首尾开始遍历。基本框架已经确定,接下来就是敲定判断的细节了。首先考虑极限条件,输入的没有字母left会一直加,越界了;所以处理left和right时要加上判断条件。

<code>class Solution {

public:

bool Isletter(char ch)

{

if (ch >= 'a' && ch <= 'z')

{

return true;

}

if (ch >= 'A' && ch <= 'Z')

{

return true;

}

return false;

}

string reverseOnlyLetters(string s) {

if (s.empty())

{

return s;

}

size_t left = 0;

size_t right = s.size() - 1;

while(left < right)

{

while(left < right && !Isletter(s[left]))

{

left++;

}

while(left < right && !Isletter(s[right]))

{

right--;

}

swap(s[left++],s[right--]);

}

return s;

}

};



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。