【编码艺术:掌握String类函数接口的妙用指南】(一)

简介: 【编码艺术:掌握String类函数接口的妙用指南】

【本节目标】


  • 1. 为什么要学习string类
  • 2. 标准库中的string类


1. 为什么要学习string类


1.1 C语言中的字符串


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


2. 标准库中的string类


2.1 string类(了解)


string类的文档介绍


总结:

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

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

3. string在底层实际是:basic_string模板类的别名,typedef basic_string string;

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


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


2.2 string类的常用接口说明


1. string类对象的常见构造


void Teststring()
{
  string s1; // 构造空的string类对象s1
  string s2("hello bit"); // 用C格式字符串构造string类对象s2
  string s3(s2); // 拷贝构造s3
  string s4 = s3;// 拷贝构造s4
}

我们再来介绍一下string其他相关的构造


(3)Copies the portion(一部分) of str that begins at the character position pos and spans(跨越) len characters (or until the end of str, if either str is too short or if len is string::npos).


我们来使用一下该函数:

string (const string& str, size_t pos, size_t len = npos);


我们再来看一下npos是什么?


所以我们就可以完全理解上面的函数:复制字符串 str 从字符位置 pos 开始,跨越 len 个字符(或者直到 str 的末尾,如果 str 太短或 lenstring::npos)的部分。


(5)Copies the first n characters from the array of characters pointed by s.


我们来使用一下该函数:


string (const char* s, size_t n);


这个构造函数比较简单,就是复制字符数组 s 指向的前 n 个字符,不过这里要注意该函数的第一个参数是字符串,而不是string类滴对象。


(5)Fills the string with n consecutive(连续的) copies of characterc.


我们来使用一下该函数:


string (size_t n, char c);


这个构造函数就是用字符 c 的连续副本填充字符串,填充的数量为 n。


(7)Copies the sequence of characters in the range [first,last), in the same order.


这个构造函数涉及迭代器,我们后面再讲解。


2.string类对象的析构函数



析构函数会自动调用的,我们可以不用重点关注在这一块。


3. string类对象的赋值



这里赋值可以支持string类的对象常量字符串字符


4. string类对象的遍历和访问



4.1.通过下标 + [ ]运算符重载实现


//遍历和访问
int main()
{
  string str("Test string");
  //下面两个函数结果相同,结果是不包含'\0'的
  cout << "size:" << str.size() << endl;//推荐使用
  cout << "length:" << str.length() << endl;
  for (size_t i = 0; i < str.size(); i++)
  {
    cout << str[i];
  }
  cout << endl;
  return 0;
}


运行结果:


我们再来写一个字符串的逆序

//字符串的逆序
int main()
{
  string str("Test string");
  int begin = 0, end = str.size() - 1;
  while (begin < end)
  {
    char tmp = str[begin];
    str[begin] = str[end];
    str[end] = tmp;
    ++begin;
    --end;
  }
  for (size_t i = 0; i < str.size(); i++)
  {
    cout << str[i];
  }
  cout << endl;
  return 0;
}


上面的逆序字符串交换的这个代码很繁琐,C++为我们提供了Swap函数接口


于是我们根据上面的swap函数就可以这样写

//字符串的逆序
int main()
{
  string str("Test string");
  int begin = 0, end = str.size() - 1;
  while (begin < end)
  {
    swap(str[begin], str[end]);
    ++begin;
    --end;
  }
  for (size_t i = 0; i < str.size(); i++)
  {
    cout << str[i];
  }
  cout << endl;
  return 0;
}


运行结果:


我们现在再来看一个细节,也就是我们之前提到的const的成员函数,这里的[ ]运算符重载实现了两个,这里是两个不同的函数,它们的参数是不同的,第二个隐形的this指针用了const修饰,这里我们要提一下参数匹配的问题。


#include <iostream>
#include <string>
using namespace std;
int main()
{
  string s1("hello world");
  const string s2("hello world");
  // 如果只实现了const char& operator[] (size_t pos) const;
  s1[0];//权限缩小
  s2[0];//权限平移
  // 但是此时返回值是const char& - 返回值不可修改
  //s2[0] = 'x';//error:error C3892: “s2”: 不能给常量赋值
  //所以就提供了char& operator[] (size_t pos);
  s1[0] = 'x';
  return 0;
}


4.2.迭代器(Iterator)


//迭代器iterator:遍历和访问
int main()
{
  string str("Test string\0");
  //定义在类域里面,需要域作用限定符才可以访问
  //迭代器iterator是一个类型,用法像指针
  //[begin,end)左边右开区间
  string::iterator it = str.begin();
  while (it != str.end())
  {
    *it += 1;//访问修改
    cout << *it;//遍历
    ++it;
  }
  cout << endl;
  return 0;
}


运行结果:


解析:


总结:虽然下标 + [ ]很方便,但是它仅仅适用于这些底层物理空间连续,比如string、vector等等。但是链式结构,树形和哈希结构,只能用迭代器,迭代器才是容器访问主流形态。


所以我们上面的逆序就不用写上面的这么多代码,C++为我们提供了逆置的函数:reverse


所以就可以直接这样写:

//字符串的逆序
int main()
{
  string str("Test string");
  string::iterator it = str.begin();
  reverse(str.begin(), str.end());
  while (it != str.end())
  {
    cout << *it;
    ++it;
  }
  cout << endl;
  return 0;
}


运行结果:


上面通过函数模板实现,注意泛型编程不是针对某个容器的迭代器实现的,函数模板是针对各个容器迭代器实现。关于我们的迭代器,begin获取一个字符的迭代器,end获取最后一个字符下一个位置,普通的迭代器是可读可写的,但是这里也有一个细节,我们这里迭代器也实现了重载,const重载的只能进行可读。


当我们对只读对象进行迭代器遍历的时候,就出现错误了。同时这里还有一个细节,我们发现上面是const_iterator,而不是const iterator,中间多了一个_,这里的const_iterator本质上是保护迭代器指向的数据"*it"不能被修改,而不是const iterator是迭代器本身不能被修改,也就"it"不能被修改,否则这样无法++,无法遍历,不符合我们的需求。


4.3.反向迭代器


我们也可以通过反向迭代器进行遍历和访问,但是此时的遍历是逆序的。


样例:


我们可以观察到反向迭代器也实现了两个版本,但是普通情况下我们基本上很少定义const对象,只有在传参的时候我们才最容易出现const对象。

//void fun(const string s1){}//调用拷贝构造,深拷贝,代价大
void fun(const string& s1)//引用,作为str的别名,开销小
{
  //error
  //string::reverse_iterator it = s1.rbegin();
  //const的对象调用rbegin应该返回const_reverse_iterator
  string::const_reverse_iterator it = s1.rbegin();
  while (it != s1.rend())
  {
    *it = 1;//const迭代器不可修改,error:“it”: 不能给常量赋值  
    cout << *it;
    ++it;
  }
  cout << endl;
}
int main()
{
  string str("Test string");
  string::reverse_iterator it = str.rbegin();
  while (it != str.rend())
  {
    *it = 1;//普通迭代器不可修改
    cout << *it;
    ++it;
  }
  cout << endl;
  fun(str);
  return 0;
}


【编码艺术:掌握String类函数接口的妙用指南】(二):https://developer.aliyun.com/article/1425650

相关文章
|
23天前
|
存储 编译器 C语言
【c++丨STL】string类的使用
本文介绍了C++中`string`类的基本概念及其主要接口。`string`类在C++标准库中扮演着重要角色,它提供了比C语言中字符串处理函数更丰富、安全和便捷的功能。文章详细讲解了`string`类的构造函数、赋值运算符、容量管理接口、元素访问及遍历方法、字符串修改操作、字符串运算接口、常量成员和非成员函数等内容。通过实例演示了如何使用这些接口进行字符串的创建、修改、查找和比较等操作,帮助读者更好地理解和掌握`string`类的应用。
37 2
|
2月前
|
Java
【编程基础知识】(讲解+示例实战)方法参数的传递机制(值传递及地址传递)以及String类的对象的不可变性
本文深入探讨了Java中方法参数的传递机制,包括值传递和引用传递的区别,以及String类对象的不可变性。通过详细讲解和示例代码,帮助读者理解参数传递的内部原理,并掌握在实际编程中正确处理参数传递的方法。关键词:Java, 方法参数传递, 值传递, 引用传递, String不可变性。
67 1
【编程基础知识】(讲解+示例实战)方法参数的传递机制(值传递及地址传递)以及String类的对象的不可变性
|
2月前
|
安全 Java 测试技术
Java零基础-StringBuffer 类详解
【10月更文挑战第9天】Java零基础教学篇,手把手实践教学!
49 2
|
2月前
|
存储 安全 C++
【C++打怪之路Lv8】-- string类
【C++打怪之路Lv8】-- string类
26 1
|
2月前
|
数据可视化 Java
让星星月亮告诉你,通过反射创建类的实例对象,并通过Unsafe theUnsafe来修改实例对象的私有的String类型的成员属性的值
本文介绍了如何使用 Unsafe 类通过反射机制修改对象的私有属性值。主要包括: 1. 获取 Unsafe 的 theUnsafe 属性:通过反射获取 Unsafe类的私有静态属性theUnsafe,并放开其访问权限,以便后续操作 2. 利用反射创建 User 类的实例对象:通过反射创建User类的实例对象,并定义预期值 3. 利用反射获取实例对象的name属性并修改:通过反射获取 User类实例对象的私有属性name,使用 Unsafe`的compareAndSwapObject方法直接在内存地址上修改属性值 核心代码展示了详细的步骤和逻辑,确保了对私有属性的修改不受 JVM 访问权限的限制
62 4
|
2月前
|
存储 安全 Java
【一步一步了解Java系列】:认识String类
【一步一步了解Java系列】:认识String类
28 2
|
2月前
|
C语言 C++
C++番外篇——string类的实现
C++番外篇——string类的实现
22 0
|
3月前
|
Java 索引
java基础(13)String类
本文介绍了Java中String类的多种操作方法,包括字符串拼接、获取长度、去除空格、替换、截取、分割、比较和查找字符等。
44 0
java基础(13)String类
|
3月前
|
安全 Java
String类-知识回顾①
这篇文章回顾了Java中String类的相关知识点,包括`==`操作符和`equals()`方法的区别、String类对象的不可变性及其好处、String常量池的概念,以及String对象的加法操作。文章通过代码示例详细解释了这些概念,并探讨了使用String常量池时的一些行为。
String类-知识回顾①
|
2月前
|
安全 C语言 C++
【C++篇】探寻C++ STL之美:从string类的基础到高级操作的全面解析
【C++篇】探寻C++ STL之美:从string类的基础到高级操作的全面解析
45 4