深度剖析C++string(上篇)(1)

简介: 深度剖析C++string(上篇)(1)

前言

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

1.C++ string类

C++中的string类是STL的一个重要组成部分,它提供了对字符串的封装和处理功能。

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

下面是参考的官方链接

http://www.cplusplus.com/reference/string/string/?kw=string

接下来,我们将进一步学习string类。

2.string类中的常见构造

#include <iostream>
#include <string>
using namespace std;
int main() {
  string s1;
  string s2("hello world");
  string s3(6, 'x');
  string s4(s3);
  cout << s1 << endl;
  cout << s2 << endl;
  cout << s3 << endl;
  cout << s4 << endl;
  return 0;
}

3.string类对象的容量操作

函数名称功能说明

size(重点)返回字符串有效字符长度

length 返回字符串有效字符长度

capacity返回空间总大

void string1() {
  string s("I love you!!!");
  cout << s.size() << endl;
  cout << s.length() << endl;
  cout << s.capacity() << endl;
  cout << s << endl;
}

在C++的string类中,size()length()成员函数返回的是字符串中字符的数量,不包括结尾的空字符(\0),因为string类内部管理内存时会自动在字符串末尾添加一个空字符,但这个空字符不计入字符串的长度。

capacity()成员函数返回的是字符串当前分配的内存能够容纳的字符数量,这个值通常大于或等于size()的返回值,以容纳未来可能的字符添加操作,而不会立即触发重新分配内存。

empty (重点)检测字符串释放为空串,是返回true,否则返回false

clear (重点)清空有效字符

reserve (重点)为字符串预留空间**

resize (重点)将有效字符的个数该成n个,多出的空间用字符c填充

void string1() {
  string s("I love you!!!");
  cout << s.size() << endl;
  cout << s.length() << endl;
  cout << s.capacity() << endl;
  cout << s << endl;
  // 使用empty()检查字符串是否为空
  if (s.empty()) {
    cout << "s is empty." << endl;
  }
  else {
    cout << "s is not empty." << endl;
  }
  //s.clear();
  //cout << s.size() << endl;
  ///cout << s.capacity() << endl;
  //cout << s << endl;
  s.resize(18, 'a');
  //s.resize(6);
  cout << s.size() << endl;
  cout << s.capacity() << endl;
  cout << s << endl;
}

可根据自己的需求自行更改代码。不难发现capacity 的大小会根据字符串的大小变化可能进行相应的变化,变化情况见上capacity的介绍。linux下gcc和VS的capacity变化规则是略有不同的,大家可以下去尝试下。

void string2()
{
  string s;
  // 测试reserve是否会改变string中有效元素个数
  s.reserve(100);
  cout << s.size() << endl;
  cout << s.capacity() << endl;
  // 测试reserve参数小于string的底层空间大小时,是否会将空间缩小
  s.reserve(50);
  cout << s.size() << endl;
  cout << s.capacity() << endl; //输出原来值或更大,不会缩小
}
void TestPushBack() {
  string s;
  size_t sz = s.capacity();
  cout << "capacity: " << sz << '\n';
  cout << "making s grow:\n";
  for (int i = 0; i < 100; ++i)
  {
    s.push_back('c');
    if (sz != s.capacity())
    {
      sz = s.capacity();
      cout << "capacity changed: " << sz << '\n';
    }
  }
}

当把\0加上时,我们会发现刚开始的变化是2倍,后面是1.5倍,这是VS自己规定的变化规则,刚开始会默认开设一个大小为16字节的数组,后面变化的空间是在堆上的。

而gcc运行此代码都是2倍的变化。

注意:

1. size()与length()方法底层实现原理完全相同,引入size()的原因是为了与其他容器的接 口保持一致,一般情况下基本都是用size()。

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

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

4. reserve(size_t res_arg=0):为string预留空间,不改变有效元素个数,当reserve的参数小于string的底层空间总大小时,reserver不会改变容量大小。

vs和g++下string结构的说明(了解),小编也没有理解的通透。

注意:下述结构是在32位平台下进行验证,32位平台下指针占4个字节。

vs下string的结构 string总共占28个字节,内部结构稍微复杂一点,先是有一个联合体,联合体用来定义 string中字符串的存储空间:

当字符串长度小于16时,使用内部固定的字符数组来存放。 当字符串长度大于等于16时,从堆上开辟空间

union _Bxty { // storage for small buffer or pointer to larger one

value_type _Buf[_BUF_SIZE];

pointer _Ptr;

char _Alias[_BUF_SIZE];

// to permit aliasing } _Bx;

这种设计也是有一定道理的,大多数情况下字符串的长度都小于16,那string对象创建 好之后,内部已经有了16个字符数组的固定空间,不需要通过堆创建,效率高。

其次:还有一个size_t字段保存字符串长度,一个size_t字段保存从堆上开辟空间总的容量 最后:还有一个指针做一些其他事情。 故总共占16+4+4+4=28个字节。

g++下string的结构

G++下,string是通过写时拷贝实现的,string对象总共占4个字节,内部只包含了一个 指针,该指针将来指向一块堆空间,内部包含了如下字段:

空间总大小 字符串有效长度 引用计数

指向堆空间的指针,用来存储字符串

深度剖析C++string(上篇)(2):https://developer.aliyun.com/article/1624973


目录
相关文章
|
24天前
|
C语言 C++ 容器
【c++丨STL】string模拟实现(附源码)
本文详细介绍了如何模拟实现C++ STL中的`string`类,包括其构造函数、拷贝构造、赋值重载、析构函数等基本功能,以及字符串的插入、删除、查找、比较等操作。文章还展示了如何实现输入输出流操作符,使自定义的`string`类能够方便地与`cin`和`cout`配合使用。通过这些实现,读者不仅能加深对`string`类的理解,还能提升对C++编程技巧的掌握。
50 5
|
24天前
|
存储 编译器 C语言
【c++丨STL】string类的使用
本文介绍了C++中`string`类的基本概念及其主要接口。`string`类在C++标准库中扮演着重要角色,它提供了比C语言中字符串处理函数更丰富、安全和便捷的功能。文章详细讲解了`string`类的构造函数、赋值运算符、容量管理接口、元素访问及遍历方法、字符串修改操作、字符串运算接口、常量成员和非成员函数等内容。通过实例演示了如何使用这些接口进行字符串的创建、修改、查找和比较等操作,帮助读者更好地理解和掌握`string`类的应用。
38 2
|
2月前
|
C++ 容器
|
2月前
|
存储 安全 C++
【C++打怪之路Lv8】-- string类
【C++打怪之路Lv8】-- string类
26 1
|
2月前
|
C++ 容器
|
2月前
|
C++ 容器
|
2月前
|
存储 C++ 容器
|
2月前
|
安全 C语言 C++
【C++篇】探寻C++ STL之美:从string类的基础到高级操作的全面解析
【C++篇】探寻C++ STL之美:从string类的基础到高级操作的全面解析
46 4
|
2月前
|
存储 编译器 程序员
【C++篇】手撕 C++ string 类:从零实现到深入剖析的模拟之路
【C++篇】手撕 C++ string 类:从零实现到深入剖析的模拟之路
74 2
|
2月前
|
编译器 C语言 C++
【C++】C++ STL 探索:String的使用与理解(三)
【C++】C++ STL 探索:String的使用与理解