从C语言到C++_11(string类的常用函数)力扣58和415(上)

简介: 从C语言到C++_11(string类的常用函数)力扣58和415

此篇算是STL的正式学习,string类的许多操作和以后很多的操作都是一样的,

所以此篇文章的接口函数讲得细一点,以后学习就会舒服很多。

1. 学习string的铺垫

语言中的字符串,是以 \0 为结尾的一些字符的集合。

为了方便操作,C标准库中提供了一些 str 系列的库函数。

但是这些库函数与字符串是分离开的,不太符合面向对象的思想。

而且底层空间需要用户自己管理,一不小心还会造成越界访问,很不方便。  

在工作中为了方便大多会使用 string 类,很少有人去使用 C 标准库中的字符串函数。

1.1 什么是string类

简单来说,string 就是一个管理字符串的类。

上一篇说的查文档: string - C++ Reference(string类的文档介绍)

① 字符串是表示字符序列的类。

② 标准的字符串提供了对此类对象的支持,其接口类似于标准字符容器的接口,

    但添加了专门用于操作单字节字符串的设计特性。

③ string 类是使用 char,即作为它的字符类型,使用它的默认 char_traits 和分配器类型。

  (关于模板的更多信息,可以参阅 basic_string)

④ string类是 basic_sting 模板类的一个实例,它使用 char 来实例化 basic_string 模板类,

    并用 char_traits 和 allocator 作为 basic_string 的默认参数。

   (关于更多的模板信息请参考 basic_sting )

⑤ 注意,这个类独立于所使用的编码来处理字节。

    如果用来处理多字节或变长字符(如UTF-8)的系列,这个类的所有成员(如长度或大小)以及它的迭代器,将仍然按照字节(而不是实际编码的字符)来操作。

总结:

① string 是表示字符串的字符串类。

② 该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作 string 的常规操作。

③ string在底层上实际是:basic_string 模板类的别名:

typedef basic_string<char, char_traits, allocator>string;

④ 不能操作多字节或者变长字符的序列。

使用 string 类时,必须包含#include 头文件以及using namespace std ;

1.2 basic_string 模板类

在正式开始讲解 string 之前,还要介绍一下刚才提到的 basic_string 模板类:

typedef basic_string<char, char_traits, allocator>string;

从文档中可以看出,string 的原生类并不是直接定义了一个 string 类,而是定义出了一个类模板。

而 string 是用 typedef 出来的,它其实是 basic_string

我们先用 C 格式字符串构造一个 string 类对象:

#include <iostream>
#include <string>
using namespace std;
 
int main()
{
  string str("hello world");
 
  return 0;
}

既然我们知道了它是  basic_string  ,我们来猜想一下它在库里面是如何定义的:

template<class T>
class basic_string 
{
private:
  T* _str;
  // ...
};

这里为什么需要模板?管理字符串不就是一个 char 吗?搞一个模板出来干什么?

字符串还有其它类型?这和编码有关系,这里稍微补充一下关于编码的知识。

1.3 编码表的由来

我们知道,计算机是约翰·冯·诺依曼发明的,早期在计算机上是只需要显示英文的。

英文的显示非常简单,英文字母一组合就是英文单词了,


大写字母 + 小写字母,再加上一些标点符号,顶多也就一百多个字符,


所以出现了一套 ASCII 码。比如说你写了一个 'a' ,想在计算机中存储,因为计算机只有二进制,


虽然  和  只能表示两种状态,但是多个  和  一组合就可以表示出很多状态了。

为了能够记录这些字符,于是就建立了一个映射。值映射符号,于是就产生了编码表:

ASCII ((American Standard Code for Information Interchange): 美国信息交换标准代码)

是基于拉丁字母的一套电脑编码系统,主要用于显示现代英语和其他西欧语言。"

虽然英文是世界通用语言,但也不是所有人都懂英文啊。

为了能让计算机更好地普及,这时候就有人搞出了 Unicode——表示全世界文字的编码表。

"统一码(Unicode),也叫万国码、单一码,是计算机科学领域里的一项业界标准,包括字符集、编码方案等。Unicode是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。"

utf-8,常见的汉字都用2个字节去编,一些生僻的可以用3个或者4个……

(我们常说的 utf-8   utf-16   utf-32 )

你可以理解为,中文有了一套自己的规则,去找到值对应的汉字。

存的时候存的是 utf-8 对应的值,你要用的时候它就会拿这个表去查。

要对应的上,如果对应不上就会出现我们熟知的乱码。

所以建议在Linux或服务器下统一把编码设置为 utf-8,不然出现乱码会很恶心。

我们已经知道,Unicode 是世界通用编码,而我们中国也有一套自己的编码方式。

GBK —— 中文自己量身定做的编码表。

"GBK全称《汉字内码扩展规范》(GBK即“国标”、“扩展”汉语拼音的第一个字母,英文名称:Chinese Internal Code Specification)"

如果你打开一个文本,Windows 下一般默认的编码是GBK,Linux 下默认的就是 utf-8 。

GBK包括所有的汉字,包括简体和繁体。而这里显示的 GB2312 则只包括简体汉字。

(读音相同的字是编到一起的,打游戏时的C语言被屏蔽就能被体现)

回到刚才的问题 —— string 需要模板的原因:

刚才介绍了编码,现在大家应该能理解为什么 string 需要模板了。

string 不仅要存 char,还有 wchar_t (2个字节)char 16_t,char32 _t 等等,

这就是 string 需要 basic_sting 的原因。

1.4 其它字符编码的string

宽字节是一种扩展的存储方式,unicode 编码的字符一般以 wchar_t 类型存储。

wchar_t 是两个字节,是为了更好地表示字符。

如果涉及 Windows 编程,Windows 下的很多接口都是用的 Unicode,

这时它的字符串不是 char*,而是 wchar_t* ,这时候就涉及到转码,

如果想要存储 wchar_t* ,就最好用 wstring —— 专门处理宽字符的。

概念:wstring 就是每个字符都是一个 wchar_t 的:

不仅仅有 string 和 wstring!

还有 u16string(存16个比特位)、还有u32string(存32个比特位)

总结:

本章主要学习 string,现阶段基本用的都是 string (里面存 char)

如果碰到有些地方是 wchar_t 就要使用与之对应的 wstring 了,

其他也一样,比如有些地方字符串编码是 utf-32,这时候你就可能要用 u32string 去存储了。

因为有的库或API只支持UTF-16编码的字符,

而且有的API使用UTF-16编码的字符时执行速度会快一些。

2. string类对象的常见构造

我们还是以查看文档的方式去学习:

#include <iostream>
#include <string>
using namespace std;
 
void test_string1()
{
  string s1; // 构造空的string类对象s1
  string s2("hello world"); // 用C格式字符串构造string类对象s2
  string s3(s2); // 拷贝构造s3
 
  cout << s1 << endl;
  cout << s2 << endl;
  cout << s3 << endl;
 
  string s4(s2, 6, 3);//从第6个位置开始向后面拷贝3个字母
  cout << s4 << endl;
 
  string s5(s2, 6, 15);// 第三个参数len大于后面字符长度,有多少拷贝多少拷贝到结尾
  cout << s5 << endl;
  string s6(s2, 6);// 第三个参数默认给npos,是整形的最大值,相当于取所有字符串
  cout << s6 << endl;
 
  string s7(10, 'x');// 用10个x构造s7
  cout << s7 << endl;
}
int main()
{
  test_string1();
 
  return 0;
}

3. sting类对象的容量操作

注意事项:

①  size() 和 length() 的计算不包含 \0。

    解释:它不包含最后作为结尾标识符的 \0,告诉你的是有效的字符长度。

②  size() 和 length() 的功能都是返回字符串有效长度,功能上没有区别

    解释: 这是一个 "历史包袱" 问题。

因为 string 比 STL 出现的还要早一些,有了STL容器后,为了和树等对应上所以给出了 size() 。

而 length() 是代替传统的C字符串,所以针对C中的 strlen ,给出相应的函数 length() 。

C++中 string 成员函数 length() 等同于 size() ,功能没有任何区别。

不信可以看 C++标准库中的 string 中 size() 和 length() 的源代码:

size_type   __CLR_OR_THIS_CALL   length()   const
{   //   return   length   of   sequence
    return   (_Mysize);
}
 
size_type   __CLR_OR_THIS_CALL   size()   const
{   //   return   length   of   sequence
    return   (_Mysize);
} 

③ clear 只是把数据清了,但是容量还在。

④ reserve 开空间,影响容量。

   而 resize 是开空间,并对这些空间给一个初始值,进行初始化。(不指定默认用 \0 初始化)

void test_string2()
{
  string s1("hello world");
  cout << s1.size() << endl;
  cout << s1.length() << endl;
  cout << s1.capacity() << endl;
  cout << s1.empty() << endl;
 
  cout << s1 << endl;
  s1.clear();
  cout << s1 << endl;;
 
  string s2;
  cout << s2.capacity() << endl;// 不同编译器的原始值不同,扩容也不同
  s2.reserve(1000);// 实际考虑内存对齐什么的,会多预留一点
  cout << s2.capacity() << endl;
 
  string s3("hello world");
  cout << s3.size() << endl;
  s3.resize(50, 'x');
  cout << s3 << endl;
}


resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不同的是当字符个数增多时:resize(n)用0来填充多出的元素空间,resize(size_t n, char c)用字符c来填充多出的 元素空间。注意:resize在改变元素个数时,如果是将元素个数增多,可能会改变底层容量的大 小,如果是将元素个数减少,会删除后面数据,底层空间总大小不变。

reserve 为string预留空间,不改变有效元素个数,当reserve的参数小于 string的底层空间总大小时,reserver不会改变容量大小,大于才会。

从C语言到C++_11(string类的常用函数)力扣58和415(中):https://developer.aliyun.com/article/1513667

目录
相关文章
|
3月前
|
存储 C语言
`scanf`是C语言中用于按格式读取标准输入的函数
`scanf`是C语言中用于按格式读取标准输入的函数,通过格式字符串解析输入并存入指定变量。需注意输入格式严格匹配,并建议检查返回值以确保读取成功,提升程序健壮性。
1009 0
|
5月前
|
安全 C语言 C++
比较C++的内存分配与管理方式new/delete与C语言中的malloc/realloc/calloc/free。
在实用性方面,C++的内存管理方式提供了面向对象的特性,它是处理构造和析构、需要类型安全和异常处理的首选方案。而C语言的内存管理函数适用于简单的内存分配,例如分配原始内存块或复杂性较低的数据结构,没有构造和析构的要求。当从C迁移到C++,或在C++中使用C代码时,了解两种内存管理方式的差异非常重要。
202 26
|
5月前
|
安全 C语言
C语言中的字符、字符串及内存操作函数详细讲解
通过这些函数的正确使用,可以有效管理字符串和内存操作,它们是C语言编程中不可或缺的工具。
325 15
|
6月前
|
人工智能 机器人 编译器
c++模板初阶----函数模板与类模板
class 类模板名private://类内成员声明class Apublic:A(T val):a(val){}private:T a;return 0;运行结果:注意:类模板中的成员函数若是放在类外定义时,需要加模板参数列表。return 0;
174 0
|
6月前
|
Java C++
力扣第一道困难题《3. 无重复字符的最长子串》,c++
首先我们看到这个题是肯定有一种暴力的硬解思路的,那就是将两个vector直接链接起来,然后再排序后,直接返回中间值,这个方法实现起来还是非常容易的,
146 0
|
6月前
|
存储 编译器 程序员
c++的类(附含explicit关键字,友元,内部类)
本文介绍了C++中类的核心概念与用法,涵盖封装、继承、多态三大特性。重点讲解了类的定义(`class`与`struct`)、访问限定符(`private`、`public`、`protected`)、类的作用域及成员函数的声明与定义分离。同时深入探讨了类的大小计算、`this`指针、默认成员函数(构造函数、析构函数、拷贝构造、赋值重载)以及运算符重载等内容。 文章还详细分析了`explicit`关键字的作用、静态成员(变量与函数)、友元(友元函数与友元类)的概念及其使用场景,并简要介绍了内部类的特性。
266 0
|
8月前
|
编译器 C++ 容器
【c++11】c++11新特性(上)(列表初始化、右值引用和移动语义、类的新默认成员函数、lambda表达式)
C++11为C++带来了革命性变化,引入了列表初始化、右值引用、移动语义、类的新默认成员函数和lambda表达式等特性。列表初始化统一了对象初始化方式,initializer_list简化了容器多元素初始化;右值引用和移动语义优化了资源管理,减少拷贝开销;类新增移动构造和移动赋值函数提升性能;lambda表达式提供匿名函数对象,增强代码简洁性和灵活性。这些特性共同推动了现代C++编程的发展,提升了开发效率与程序性能。
308 12
|
9月前
|
编译器 C++
类和对象(中 )C++
本文详细讲解了C++中的默认成员函数,包括构造函数、析构函数、拷贝构造函数、赋值运算符重载和取地址运算符重载等内容。重点分析了各函数的特点、使用场景及相互关系,如构造函数的主要任务是初始化对象,而非创建空间;析构函数用于清理资源;拷贝构造与赋值运算符的区别在于前者用于创建新对象,后者用于已存在的对象赋值。同时,文章还探讨了运算符重载的规则及其应用场景,并通过实例加深理解。最后强调,若类中存在资源管理,需显式定义拷贝构造和赋值运算符以避免浅拷贝问题。
|
9月前
|
编译器 C++
类和对象(下)C++
本内容主要讲解C++中的初始化列表、类型转换、静态成员、友元、内部类、匿名对象及对象拷贝时的编译器优化。初始化列表用于成员变量定义初始化,尤其对引用、const及无默认构造函数的类类型变量至关重要。类型转换中,`explicit`可禁用隐式转换。静态成员属类而非对象,受访问限定符约束。内部类是独立类,可增强封装性。匿名对象生命周期短,常用于临时场景。编译器会优化对象拷贝以提高效率。最后,鼓励大家通过重复练习提升技能!
|
2月前
|
编解码 Java 开发者
Java String类的关键方法总结
以上总结了Java `String` 类最常见和重要功能性方法。每种操作都对应着日常编程任务,并且理解每种操作如何影响及处理 `Strings` 对于任何使用 Java 的开发者来说都至关重要。
308 5

热门文章

最新文章