【C++STL基础入门】string迭代器

简介: 【C++STL基础入门】string迭代器

前言


本系列STL使用VS2022+C++20版本

在C++中,标准模板库(Standard Template Library,STL)是一组强大的通用模板类和函数,它为我们提供了很多供使用的数据结构和算法。其中,string类是STL中一个非常有用的类,用于处理字符串。在使用string类时,我们经常需要遍历字符串的每个字符或者进行某些特定的操作。而实现遍历和操作的关键就是使用string迭代器。本文将详细介绍string迭代器的使用方法及其在处理字符串时的重要作用。


一、迭代器是什么?


当我们需要遍历一个集合(比如数组、列表或字符串)中的元素时,就像一个一个看每个元素,这时候迭代器就派上用场了。迭代器就像是一个指针,它可以帮助我们在集合中逐个地获取其中的元素,并且可以根据需要进行修改。你可以把迭代器想象成一个遥控器,可以让我们在集合中前进、后退,或者指向特定的元素。使用迭代器,我们不需要关心集合内部的具体实现细节,只需要专注于每个元素的访问和操作。


迭代器提供了一种抽象的方法来处理集合中的元素,它可以让我们在遍历过程中轻松访问每个元素,而不必担心底层数据结构是什么样的。迭代器分为不同的类型,每种类型有着特定的目的和功能。例如,我们可以使用迭代器来读取集合元素的值,也可以使用迭代器来修改元素的值,甚至可以删除或添加元素。


总的来说,迭代器是一种工具,帮助我们在集合中按照一定的顺序遍历和操作每个元素,使得我们能够更方便地处理集合中的数据。使用迭代器,我们可以以一种统一的方式处理不同类型的集合,提高了代码的可复用性和灵活性。


二、string迭代器


1.定义迭代器

使用string类中的静态类成员iterator

string::iterator ite;

1e1b8df94769428e9af41c792f41e12a.png

理解

当我们说到迭代器时,可以将其想象为一个类似于指针的对象,它允许我们在容器(例如字符串)中按顺序访问元素或字符。


对于字符串(std::string),我们可以使用迭代器来遍历其中的字符。迭代器可以帮助我们逐个访问字符串中的每个字符,从头到尾,或者反向从尾到头。


想象一下,你有一串字母,比如 “Hello”,可以将迭代器看作是一根指向字符的手指。开始时,指向字符串的开头,即 ‘H’。然后,你可以通过移动指针(迭代器)来访问下一个字符,指向 ‘e’,再移动指针指向 ‘l’,以此类推,直到访问到最后一个字符 ‘o’。


2.通过迭代器遍历

使用迭代器,你可以根据需要遍历字符串的每个字符,无需手动跟踪当前位置或使用索引。迭代器本质上是一个帮助我们在容器中移动并访问元素的工具。


遍历方式1

for (ite = str.begin();ite != str.end(); ite++)
{
  cout << *ite;
}

1e00ddd11f2f460caaf449558912392c.png

使用+,-运算符可以移动迭代器的位置


遍历方式2

for (size_t i = 0;i < str.size(); i++)
{
  cout << ite[i];
}


37902185e8c3429ebcf7478980dac2a7.png

可以使用下标运算符进行偏移


3.迭代器失效

当我们在遍历或修改容器(例如字符串)时,迭代器可以帮助我们定位我们当前所处理的位置。然而,有些操作可能会导致迭代器失效。迭代器失效意味着先前获取的迭代器不能再安全地用于访问或修改容器中的元素。


想象一下你在一列房子前移动,每个房子都有一个门牌号(表示元素的位置)。假设你手里拿着一块纸,并且上面写着当前所处的门牌号。你可以根据纸上的门牌号找到并访问对应的房子。


然而,当进行某些操作时,例如在容器中插入或删除元素,这可能会导致房子的位置发生变化,门牌号也可能会改变。这就好像有人在你背后改变了房子的排列或增加了新的房子,导致你手里的门牌号与实际的房子位置不匹配。


在这种情况下,你手里的门牌号(即迭代器)已经失效了,不能准确地指向原来的房子。如果你继续使用失效的门牌号(迭代器),可能会导致错误的访问或修改,因为它们不再匹配实际的元素位置。


迭代器失效的情况包括:


在容器中插入或删除元素时,迭代器可能会失效。

调整容器的大小,例如重新分配内存时,迭代器可能会失效。

对容器进行排序或其他操作,可能会导致迭代器失效。

为了避免使用失效的迭代器,我们需要小心处理潜在的迭代器失效情况。一般的做法是,在进行可能导致迭代器失效的操作之后,重新获取新的迭代器来确保其有效性。


通过了解迭代器失效的原因,并谨慎处理可能导致失效的操作,我们可以更好地控制迭代器的使用,避免出现错误的访问或修改。


4.涉及到的迭代函数


1、begin()

作用:取得容器的迭代器指向容器的第一个元素。

参数:无。

返回值:迭代器,指向容器的第一个元素。


2、end()

作用:取得容器的迭代器指向容器末尾的下一个位置。

参数:无。

返回值:迭代器,指向容器末尾的下一个位置。


begin()和end()示例代码:

#include <iostream>
#include <string>
int main() {
    std::string str = "Hello";
    // Using begin() and end() to iterate over the string
    for (auto it = str.begin(); it != str.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;
    return 0;
}


64c4e8a2e3f14852b4b3be2069337bf8.png

3、append

3、append( input_iterator start, input_iterator end );

作用:将指定范围内的元素添加到容器的末尾。

参数:

start:输入迭代器,指向添加元素范围的起始位置。

end:输入迭代器,指向添加元素范围的结束位置。

示例代码:

#include <iostream>
#include <string>
#include <iterator>
int main() {
    std::string str = "Hello";
    std::string input = " World";
    // 将输入字符串 " World" 的字符追加到原始字符串 "Hello"
    str.append(input.begin(), input.end());
    std::cout << str << std::endl;  // 输出结果:Hello World
    return 0;
}


2ed095cf61344563885dc9d01300abe2.png

erase函数

4、iterator erase( iterator pos );

作用:删除容器中指定位置的元素。

参数:

pos:迭代器,指向要删除的元素位置。

返回值:迭代器,指向删除元素后的位置。

示例代码:

#include <iostream>
#include <string>
int main() {
    std::string str = "Hello, World!";
    // 删除字符串中索引为6的字符(从0开始计数)
    auto erasePos = str.begin() + 6;
    str.erase(erasePos);
    std::cout << str << std::endl;  // 输出结果:Hello World!
    return 0;
}


ffce9ad85e30437cb560363603f976e9.png

5、iterator erase( iterator start, iterator end );

作用:删除容器中指定位置的元素。

参数:

pos:迭代器,指向要删除的元素位置。

返回值:迭代器,指向删除元素后的位置。

示例代码:

#include <iostream>
#include <string>
int main() {
    std::string str = "Hello, World!";
    // 删除字符串中从索引为6到索引为12的字符(左闭右开区间)
    auto eraseStart = str.begin() + 6;
    auto eraseEnd = str.begin() + 13;
    str.erase(eraseStart, eraseEnd);
    std::cout << str << std::endl;  // 输出结果:Hello!
    return 0;
}


9039768074cf46a0ac05a3887552cef6.png

insert函数

6、void insert( iterator i, size_type num, const char &ch );

作用:在指定位置前插入多个相同元素。

参数:

i:迭代器,指向插入位置。

num:要插入的元素数量。

ch:要插入的元素值。

返回值:无。

#include <iostream>
#include <string>
int main() {
    std::string str = "Hello World";
    // 在字符串的第6个位置插入3个连续的字符 '!'
    auto insertPos = str.begin() + 6;
    size_t numChars = 3;
    char ch = '!';
    str.insert(insertPos, numChars, ch);
    std::cout << str << std::endl;  // 输出结果:Hello!!! World
    return 0;
}


aa271bca17c1449287e7a16588e60e6c.png

7、void insert( iterator i, iterator start, iterator end );

作用:在指定位置插入另一个容器中给定范围的元素。

参数:

i:迭代器,指向插入位置。

start:另一个容器的迭代器,指向插入范围的起始位置。

end:另一个容器的迭代器,指向插入范围的结束位置。

返回值:无。

示例代码:

#include <iostream>
#include <string>
int main() {
    std::string str = "Hello World";
    // 在字符串的第6个位置插入 "!!!"
    auto insertPos = str.begin() + 6;
    std::string insertStr = "!!!";
    auto start = insertStr.begin();
    auto end = insertStr.end();
    str.insert(insertPos, start, end);
    std::cout << str << std::endl;  // 输出结果:Hello!!! World
    return 0;
}


85dd7675bee240ee8600a52f690eab96.png


总结


通过本文的介绍,我们了解了string迭代器的概念和使用方法。string迭代器提供了一种便捷的方式来遍历和操作字符串中的每个字符。我们可以选择合适的迭代器类型(iterator)来满足具体的需求。使用迭代器,我们可以高效地处理字符串中的字符,进行各种操作,如修改、查找、排序等。迭代器是C++ STL中非常强大且有用的特性之一,它使得我们可以更加灵活地操作数据结构。在实际编程中,我们可以充分利用string迭代器提供的功能来简化字符串的处理和操作


希望本文能够对您理解string迭代器的基础知识有所帮助。迭代器是C++ STL中的重要概念,掌握了迭代器的使用方法,可以让我们更好地利用STL提供的各种容器和算法。

相关文章
|
9月前
|
缓存 算法 程序员
C++STL底层原理:探秘标准模板库的内部机制
🌟蒋星熠Jaxonic带你深入STL底层:从容器内存管理到红黑树、哈希表,剖析迭代器、算法与分配器核心机制,揭秘C++标准库的高效设计哲学与性能优化实践。
C++STL底层原理:探秘标准模板库的内部机制
|
编译器 C++ 容器
【c++丨STL】基于红黑树模拟实现set和map(附源码)
本文基于红黑树的实现,模拟了STL中的`set`和`map`容器。通过封装同一棵红黑树并进行适配修改,实现了两种容器的功能。主要步骤包括:1) 修改红黑树节点结构以支持不同数据类型;2) 使用仿函数适配键值比较逻辑;3) 实现双向迭代器支持遍历操作;4) 封装`insert`、`find`等接口,并为`map`实现`operator[]`。最终,通过测试代码验证了功能的正确性。此实现减少了代码冗余,展示了模板与仿函数的强大灵活性。
408 2
|
存储 算法 C++
【c++丨STL】map/multimap的使用
本文详细介绍了STL关联式容器中的`map`和`multimap`的使用方法。`map`基于红黑树实现,内部元素按键自动升序排列,存储键值对,支持通过键访问或修改值;而`multimap`允许存在重复键。文章从构造函数、迭代器、容量接口、元素访问接口、增删操作到其他操作接口全面解析了`map`的功能,并通过实例演示了如何用`map`统计字符串数组中各元素的出现次数。最后对比了`map`与`set`的区别,强调了`map`在处理键值关系时的优势。
826 73
|
存储 编译器 C语言
关于string的‘\0‘与string,vector构造特点,反迭代器与迭代器类等的讨论
你真的了解string的'\0'么?你知道创建一个string a("abcddddddddddddddddddddddddd", 16);这样的string对象要创建多少个对象么?你知道string与vector进行扩容时进行了怎么的操作么?你知道怎么求Vector 最大 最小值 索引 位置么?
308 0
|
存储 算法 C++
【c++丨STL】set/multiset的使用
本文深入解析了STL中的`set`和`multiset`容器,二者均为关联式容器,底层基于红黑树实现。`set`支持唯一性元素存储并自动排序,适用于高效查找场景;`multiset`允许重复元素。两者均具备O(logN)的插入、删除与查找复杂度。文章详细介绍了构造函数、迭代器、容量接口、增删操作(如`insert`、`erase`)、查找统计(如`find`、`count`)及`multiset`特有的区间操作(如`lower_bound`、`upper_bound`、`equal_range`)。最后预告了`map`容器的学习,其作为键值对存储的关联式容器,同样基于红黑树,具有高效操作特性。
715 3
|
存储 算法 C++
【c++丨STL】priority_queue(优先级队列)的使用与模拟实现
本文介绍了STL中的容器适配器`priority_queue`(优先级队列)。`priority_queue`根据严格的弱排序标准设计,确保其第一个元素始终是最大元素。它底层使用堆结构实现,支持大堆和小堆,默认为大堆。常用操作包括构造函数、`empty`、`size`、`top`、`push`、`pop`和`swap`等。我们还模拟实现了`priority_queue`,通过仿函数控制堆的类型,并调用封装容器的接口实现功能。最后,感谢大家的支持与关注。
987 1
|
编译器 C++ 开发者
【C++篇】深度解析类与对象(下)
在上一篇博客中,我们学习了C++的基础类与对象概念,包括类的定义、对象的使用和构造函数的作用。在这一篇,我们将深入探讨C++类的一些重要特性,如构造函数的高级用法、类型转换、static成员、友元、内部类、匿名对象,以及对象拷贝优化等。这些内容可以帮助你更好地理解和应用面向对象编程的核心理念,提升代码的健壮性、灵活性和可维护性。
|
编译器 C++ 容器
【c++11】c++11新特性(上)(列表初始化、右值引用和移动语义、类的新默认成员函数、lambda表达式)
C++11为C++带来了革命性变化,引入了列表初始化、右值引用、移动语义、类的新默认成员函数和lambda表达式等特性。列表初始化统一了对象初始化方式,initializer_list简化了容器多元素初始化;右值引用和移动语义优化了资源管理,减少拷贝开销;类新增移动构造和移动赋值函数提升性能;lambda表达式提供匿名函数对象,增强代码简洁性和灵活性。这些特性共同推动了现代C++编程的发展,提升了开发效率与程序性能。
570 12
|
编译器 C语言 C++
类和对象的简述(c++篇)
类和对象的简述(c++篇)
|
人工智能 机器人 编译器
c++模板初阶----函数模板与类模板
class 类模板名private://类内成员声明class Apublic:A(T val):a(val){}private:T a;return 0;运行结果:注意:类模板中的成员函数若是放在类外定义时,需要加模板参数列表。return 0;
301 0