当前位置:首页 » 《我的小黑屋》 » 正文

【c++】string类 (一)

3 人参与  2024年10月11日 12:00  分类 : 《我的小黑屋》  评论

点击全文阅读


简介

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

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

依然是以 '\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个构造函数,当然并不要求也没有必要对所有的函数烂熟于心,大多数时候把这个当成词典来使用就可以了,选常用的一部分学习。

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

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

#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(越界时),编译器会报错。  

#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的第一种方法就是:下标 + []

#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()返回最后一个位置的下一个位置。

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()指向第一个位置的前一个位置。这里任然要使用++,++被重载了让它能倒着遍历。 

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迭代器,只读不写。 

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

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

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的。

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

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

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()可以预留空间。

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时要加上判断条件。

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;    }};


点击全文阅读


本文链接:http://m.zhangshiyu.com/post/170479.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1