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


目录
相关文章
|
22天前
|
Java
【编程基础知识】(讲解+示例实战)方法参数的传递机制(值传递及地址传递)以及String类的对象的不可变性
本文深入探讨了Java中方法参数的传递机制,包括值传递和引用传递的区别,以及String类对象的不可变性。通过详细讲解和示例代码,帮助读者理解参数传递的内部原理,并掌握在实际编程中正确处理参数传递的方法。关键词:Java, 方法参数传递, 值传递, 引用传递, String不可变性。
45 1
【编程基础知识】(讲解+示例实战)方法参数的传递机制(值传递及地址传递)以及String类的对象的不可变性
|
19天前
|
安全 Java 测试技术
Java零基础-StringBuffer 类详解
【10月更文挑战第9天】Java零基础教学篇,手把手实践教学!
19 2
|
21天前
|
存储 安全 C++
【C++打怪之路Lv8】-- string类
【C++打怪之路Lv8】-- string类
17 1
|
24天前
|
数据可视化 Java
让星星月亮告诉你,通过反射创建类的实例对象,并通过Unsafe theUnsafe来修改实例对象的私有的String类型的成员属性的值
本文介绍了如何使用 Unsafe 类通过反射机制修改对象的私有属性值。主要包括: 1. 获取 Unsafe 的 theUnsafe 属性:通过反射获取 Unsafe类的私有静态属性theUnsafe,并放开其访问权限,以便后续操作 2. 利用反射创建 User 类的实例对象:通过反射创建User类的实例对象,并定义预期值 3. 利用反射获取实例对象的name属性并修改:通过反射获取 User类实例对象的私有属性name,使用 Unsafe`的compareAndSwapObject方法直接在内存地址上修改属性值 核心代码展示了详细的步骤和逻辑,确保了对私有属性的修改不受 JVM 访问权限的限制
48 4
|
29天前
|
存储 安全 Java
【一步一步了解Java系列】:认识String类
【一步一步了解Java系列】:认识String类
24 2
|
2月前
|
Java 索引
java基础(13)String类
本文介绍了Java中String类的多种操作方法,包括字符串拼接、获取长度、去除空格、替换、截取、分割、比较和查找字符等。
36 0
java基础(13)String类
|
3月前
|
API 索引
String类下常用API
String类下常用API
42 1
|
2月前
|
安全 Java
String类-知识回顾①
这篇文章回顾了Java中String类的相关知识点,包括`==`操作符和`equals()`方法的区别、String类对象的不可变性及其好处、String常量池的概念,以及String对象的加法操作。文章通过代码示例详细解释了这些概念,并探讨了使用String常量池时的一些行为。
String类-知识回顾①
|
1月前
|
安全 C语言 C++
【C++篇】探寻C++ STL之美:从string类的基础到高级操作的全面解析
【C++篇】探寻C++ STL之美:从string类的基础到高级操作的全面解析
33 4
|
1月前
|
存储 编译器 程序员
【C++篇】手撕 C++ string 类:从零实现到深入剖析的模拟之路
【C++篇】手撕 C++ string 类:从零实现到深入剖析的模拟之路
59 2