STL简介与String类的简单介绍(一)(下)

简介: STL(standard template libaray-标准模板库):是C++标准库的重要组成部分,不仅是一个可复用的组件库,而且 是一个包罗数据结构与算法的软件框架。通俗的未说:将常见的数据结构(顺序表,栈和队列,二叉树,堆、哈希) )以模板的方成进行了封装,以及包含了一些常见的、通用、灵活的算法。

String类:


1. 为什么学习string类?


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


2. 标准库中的string类


string类文档介绍:

image.png

1. 字符串是表示字符序列的类


2. 标准的字符串类提供了对此类对象的支持,其接口类似于标准字符容器的接口,但添加了专门用于操作 单字节字符字符串的设计特性。


3. string类是使用char(即作为它的字符类型,使用它的默认char_traits和分配器类型(关于模板的更多信 息,请参阅basic_string)。


4. string类是basic_string模板类的一个实例,它使用char来实例化basic_string模板类,并用char_traits


和allocator作为basic_string的默认参数(根于更多的模板信息请参考basic_string)。


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


总结:


1. string是表示字符串的字符串类


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


3. string在底层实际是:basic_string模板类的别名,typedef basic_string string; 4. 不能操作多字节或者变长字符的序列。 在使用string类时,必须包含#include头文件以及using namespace std;


string类的常用接口说明


1. string类对象的常见构造

image.png

2. string类对象的容量操作

image.png

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
#include <string>
// 测试string容量相关的接口
// size/clear/resize
void Teststring1()
{
  // 注意:string类对象支持直接用cin和cout进行输入和输出
  string s("hello, bit!!!");
  cout << s.size() << endl;
  cout << s.length() << endl;
  cout << s.capacity() << endl;
  cout << s << endl;
  // 将s中的字符串清空,注意清空时只是将size清0,不改变底层空间的大小
  s.clear();
  cout << s.size() << endl;
  cout << s.capacity() << endl;
  // 将s中有效字符个数增加到10个,多出位置用'a'进行填充
  // “aaaaaaaaaa”
  s.resize(10, 'a');
  cout << s.size() << endl;
  cout << s.capacity() << endl;
  // 将s中有效字符个数增加到15个,多出位置用缺省值'\0'进行填充
  // "aaaaaaaaaa\0\0\0\0\0"
  // 注意此时s中有效字符个数已经增加到15个
  s.resize(15);
  cout << s.size() << endl;
  cout << s.capacity() << endl;
  cout << s << endl;
  // 将s中有效字符个数缩小到5个
  s.resize(5);
  cout << s.size() << endl;
  cout << s.capacity() << endl;
  cout << s << endl;
}
//====================================================================================
void Teststring2()
{
  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;
}
// 利用reserve提高插入数据的效率,避免增容带来的开销
//====================================================================================
void TestPushBack()
{
  string s;
  size_t sz = s.capacity();
  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';
    }
  }
}
// 构建vector时,如果提前已经知道string中大概要放多少个元素,可以提前将string中空间设置好
void TestPushBackReserve()
{
  string s;
  s.reserve(100);
  size_t sz = s.capacity();
  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';
    }
  }
}

注意:


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不会改变容量大小(、预留空间大小:16)。


5.为什么是16?因为在日常使用的字符串一般都不会超过16,因此string内部先预留了一个数组,当元素少于16时,直接从数组上存储超过16后会在堆上申清,用空间换取时间,从堆上申请空间是有时间消耗的,b所以string类在堆上申请成功之后一般不在缩小


3. string类对象的访问及遍历操作


image.png

// string的遍历
// begin()+end()   for+[]  范围for
// 注意:string遍历时使用最多的还是for+下标 或者 范围for(C++11后才支持)
// begin()+end()大多数使用在需要使用STL提供的算法操作string时,比如:采用reverse逆置string
void Teststring3()
{
  string s1("hello Bit");
  const string s2("Hello Bit");
  cout << s1 << " " << s2 << endl;
  cout << s1[0] << " " << s2[0] << endl;
  s1[0] = 'H';
  cout << s1 << endl;
  // s2[0] = 'h';   代码编译失败,因为const类型对象不能修改
}
void Teststring4()
{
  string s("hello Bit");
  // 3种遍历方式:
  // 需要注意的以下三种方式除了遍历string对象,还可以遍历是修改string中的字符,
  // 另外以下三种方式对于string而言,第一种使用最多
  // 1. for+operator[]
  for (size_t i = 0; i < s.size(); ++i)
    cout << s[i] << endl;
  // 2.迭代器
  string::iterator it = s.begin();
  while (it != s.end())
  {
    cout << *it << endl;
    ++it;
  }
  // string::reverse_iterator rit = s.rbegin();
  // C++11之后,直接使用auto定义迭代器,让编译器推到迭代器的类型
  auto rit = s.rbegin();
  while (rit != s.rend())
    cout << *rit << endl;
  // 3.范围for
  for (auto ch : s)
    cout << ch << endl;
}


4. string类对象的修改操作


image.png

//
// 测试string:
// 1. 插入(拼接)方式:push_back  append  operator+= 
// 2. 正向和反向查找:find() + rfind()
// 3. 截取子串:substr()
// 4. 删除:erase
void Teststring5()
{
  string str;
  str.push_back(' ');   // 在str后插入空格
  str.append("hello");  // 在str后追加一个字符"hello"
  str += 'b';           // 在str后追加一个字符'b'   
  str += "it";          // 在str后追加一个字符串"it"
  cout << str << endl;
  cout << str.c_str() << endl;   // 以C语言的方式打印字符串
  // 获取file的后缀
  string file("string.cpp");
  size_t pos = file.rfind('.');
  string suffix(file.substr(pos, file.size() - pos));
  cout << suffix << endl;
  // npos是string里面的一个静态成员变量
  // static const size_t npos = -1;
  // 取出url中的域名
  string url("http://www.cplusplus.com/reference/string/string/find/");
  cout << url << endl;
  size_t start = url.find("://");
  if (start == string::npos)
  {
    cout << "invalid url" << endl;
    return;
  }
  start += 3;
  size_t finish = url.find('/', start);
  string address = url.substr(start, finish - start);
  cout << address << endl;
  // 删除url的协议前缀
  pos = url.find("://");
  url.erase(0, pos + 3);
  cout << url << endl;
}
int main()
{
  return 0;
}

注意:


1. 在string尾部追加字符时,s.push_back(c) / s.append(1, c) / s += 'c'三种的实现方式差不多,一般 情况下string类的+=操作用的比较多,+=操作不仅可以连接单个字符,还可以连接字符串。


2. 对string操作时,如果能够大概预估到放多少字符,可以先通过reserve把空间预留好。


5. string类非成员函数


image.png


6. vs和g++下string结构的说明

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


vs下string的结构:


     string总共占28个字节,内部结构稍微复杂一点,先是有一个联合体,联合体用来定义string中字 符串的存储空间: 当字符串长度小于16时,使用内部固定的字符数组来存放 当字符串长度大于等于16时,从堆上开辟空间这种设计也是有一定道理的,大多数情况下字符串的长度都小于16,那string对象创建好之后,内 部已经有了16个字符数组的固定空间,不需要通过堆创建,效率高。 其次:还有一个size_t字段保存字符串长度,一个size_t字段保存从堆上开辟空间总的容量 最后:还有一个指针做一些其他事情。 故总共占16+4+4+4=28个字节。

image.png

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;
————————————————
版权声明:本文为CSDN博主「awofe」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/awofe/article/details/128454743
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;

g++下string的结构

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

空间总大小

字符串有效长度

引用计数

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

struct _Rep_base
{
 size_type _M_length;
 size_type _M_capacity;
 _Atomic_word _M_refcount;
};


目录
相关文章
|
1天前
|
编译器 C++
【C++进阶】深入STL之string:模拟实现走进C++字符串的世界
【C++进阶】深入STL之string:模拟实现走进C++字符串的世界
|
1天前
|
安全 算法 C语言
【C++进阶】深入STL之string:掌握高效字符串处理的关键
【C++进阶】深入STL之string:掌握高效字符串处理的关键
【C++进阶】深入STL之string:掌握高效字符串处理的关键
|
2天前
|
C++ 容器
【C++语言】String 类关键函数实现,手搓一个简单字符串类!
【C++语言】String 类关键函数实现,手搓一个简单字符串类!
|
2天前
|
C++ 容器 存储
【C++语言】想学STL,先细细拿捏string类,万字详解string类 (内附精美思维导图)
【C++语言】想学STL,先细细拿捏string类,万字详解string类 (内附精美思维导图)
|
3天前
|
C++ 索引
C++ string类常用操作
C++ string类常用操作
|
3天前
Failed to bind properties under ‘logging.level‘ to java.util.Map java.lang.String, java.lang.String
Failed to bind properties under ‘logging.level‘ to java.util.Map java.lang.String, java.lang.String
4 0
|
3天前
|
安全 Java 数据安全/隐私保护
Java基础4-一文搞懂String常见面试题,从基础到实战,更有原理分析和源码解析!(二)
Java基础4-一文搞懂String常见面试题,从基础到实战,更有原理分析和源码解析!(二)
12 0
|
3天前
|
JSON 安全 Java
Java基础4-一文搞懂String常见面试题,从基础到实战,更有原理分析和源码解析!(一)
Java基础4-一文搞懂String常见面试题,从基础到实战,更有原理分析和源码解析!(一)
10 0
|
3天前
|
Java
guava Splitter 与java 内置的string的split 方法的区别
guava Splitter 与java 内置的string的split 方法的区别
5 0
|
6天前
|
Java
Java中判断String类型为空和null的方法
Java中判断`String`变量是否为空或`null`需用`== null`和`.isEmpty()`。示例代码提供两种方法:`main`方法直接判断,`safeGetString`方法提供默认值。当输入为`null`或空时,返回默认值。代码包含三个测试案例,分别处理`null`、空字符串和非空非`null`字符串。
21 0