news 2026/9/28 4:46:27

第2期|string、vector与数组

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
第2期|string、vector与数组

开篇

如果用过C语言,就会知道C语言里处理字符串要手动管内存、strcpy容易越界;C++的string帮你把这些脏活累活都干了。vector更是日常开发用得最多的容器,没有之一。

这一篇讲《C++ Primer》第3章的核心:string的常用操作、vector的动态增长、数组与指针的关系、迭代器的正确使用。

一、标准库string

string表示可变长的字符序列,使用string类型必须首先包含string头文件

#include <string>

初始化方式:

常用操作:

避坑1:size()返回无符号数。如果for (int i = 0; i <= s.size() - 1; i++),当s为空时,s.size() - 1是无符号下溢,变成一个巨大的数,循环失控。正确的做法是先判断empty(),或者直接使用i < s.size(),或者使用i + 1 < s.size()(如果确实需要遍历到倒数第二个元素),或者用std::ssize得到有符号大小。

避坑2:字符串字面值和string相加时,“+”号两边至少有一个是string。"hello" + "world"是错误的(两个const char*不能相加),但s1 + "world"是对的。

处理string对象中的字符(下图为cctype头文件中的主要函数):

二、vector动态数组

vector是标准库最常用的容器,定义在<vector>中。它是一个能自动增长的动态数组。

初始化:

常用操作:

v[n]:下标访问(不检查越界)

v.at(n):下标访问(越界抛异常)

v.pop_back():删除尾部元素

vector扩容机制(面试高频):

vector在底层是连续内存。当size达到capacity时,再push_back会触发扩容:

1. 分配一块更大的内存(通常是原来的1.5倍或2倍,因编译器而异);

2. 把旧元素拷贝/移动到新内存;

3. 销毁旧元素,释放旧内存。

关键后果:扩容后,所有指向旧内存的迭代器、指针、引用全部失效!

这就是为什么在循环中push_back要特别小心:

// 危险写法 for (auto it = v.begin(); it != v.end(); ++it) { v.push_back(*it); // 可能触发扩容,it失效! }

性能优化:如果知道大概需要多少元素,用v.reserve(n)预先分配容量,避免多次扩容拷贝。

三、迭代器

迭代器是STL的核心概念,是容器和算法之间的桥梁。所有标准库容器都支持迭代器。

auto it = v.begin(); // 指向第一个元素 auto end = v.end(); // 指向最后一个元素的下一个位置(尾后迭代器) *it; // 解引用,获取元素 ++it; // 移动到下一个元素

标准容器迭代器运算符:

迭代器类型:

1. begin/end:普通迭代器,可读写;

2. cbegin/cend:const迭代器,只读;

3. rbegin/rend:反向迭代器,从尾向头遍历。

迭代器失效场景总结:

操作

哪些迭代器失效

vector插入导致扩容

全部失效

vector中间插入

插入点之后全部失效

vector删除元素

删除点之后全部失效

list插入/删除

仅被删元素的迭代器失效

vector和string迭代器支持的运算:

四、数组与指针

C++保留了C风格数组,但《C++ Primer》明确建议:优先使用vector和string,数组只在性能极端敏感或与C接口交互时使用。

数组的特点:

1. 大小固定,编译时确定;

2. 数组名在大多数表达式中会退化为指向首元素的指针;

3. 数组不能拷贝或赋值;

4. 数组越界是未定义行为,编译器不检查;

5. 默认情况下,数组的元素被默认初始化;

6. 不存在引用的数组

7. 当使用字符串字面值对数组进行初始化时,一定要注意字符串字面值的结尾处还有一个空字符'\0'。

unsigned cnt = 42; // 不是常量表达式 constexpr unsigned sz = 42; // 常量表达式 int arr[10]; // 含有10个整数的数组 int *parr[sz]; // 含有42个整型指针的数组 int &refs[10] = /*?*/; // 错误,不存在引用的数组 int (*parray)[10] = &arr; // parray指向一个含有10个整数的数组 int (&arrRef)[10] = arr; // arrRef引用一个含有10个整数的数组 string bad[cnt]; // 错误:cnt不是常量表达式 string strs[get_size()]; // 当get_size是constexpr时正确;否则错误 int arr[5] = {1, 2, 3, 4, 5}; int *p = arr; // arr退化为&arr[0] *(p + 2); // 等价于arr[2],值为3

指针和数组的关系:下标操作本质上是指针运算。arr[i]等价于*(arr + i)。但指针是独立变量,可以改指向;数组名是常量地址,不能改。

多维数组:C++的多维数组本质是“数组的数组”。int a[3][4]是一个包含3个元素的数组,每个元素是一个包含4个int的数组。

标准库函数begin和end(定义在iterator头文件中):

为了让指针的使用更简单安全,C++11引入了begin和end。

int ia[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; int *beg = begin(ia); // 指向ia的首元素 int *last = end(ia); // 指向ia尾元素的下一位置的指针

多维数组:

使用范围for语句处理多维数组:

size_t cnt = 0; for (auto &row : ia) { for (auto &col : row) { col = cnt; ++cnt; } }

注意:要使用范围for语句处理多维数组,除了最内层的循环外,其他所有循环的控制变量都应该是引用类型(为了避免数组被自动转换成指针导致编译错误)。

指针和多维数组:

因为多维数组实际上是数组的数组,所以由多维数组名转换得来的指针实际上是指向第一个内层数组的指针。

int ia[3][4]; // 大小为3的数组,每个元素是含有4个整数的数组 int (*p)[4] = ia; // p指向含有4个整数的数组 p = &ia[2]; // p指向ia的尾元素

C++11通过auto或者decltype就能尽可能地避免在数组前面加上一个指针类型了

for (auto p = ia; p != ia + 3; ++p) for (auto q = *p; q != *p + 4; ++q) cout << *q << ' '; cout << endl;

或者

for (auto p = begin(ia); p != end(ia); ++p) for (auto q = begin(*p); q != end(*p); ++q) cout << *q << ' '; cout << endl;

本期小结

1. string自动管理内存,注意size()无符号下溢和字符串拼接规则;

2. vector扩容会使所有迭代器失效,预知大小时用reserve优化;

3. 迭代器是容器和算法的桥梁,不同容器的失效规则不同;

4. 数组名退化为指针,数组大小固定,优化使用vector替代。

下一期预告:第3期——类基础:构造、析构、访问控制、const成员函数、友元等。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/28 4:46:27

第19篇:相机参数-位置与四至——镜头此刻站哪儿、看向哪儿、框住哪块地,一次问清楚

还记得第 14 篇结尾,本猿随口留的那句话吗? 至于"当前屏幕覆盖哪块经纬度范围",本仓库里正好有一个专门的案例(CASE_LIST #19「相机参数-位置与四至」),到时候我们再细聊。 那时候我们做的是向地球要一个点的答案:鼠标落在哪儿,就问出那一点的经纬高;顺手在…

作者头像 李华
网站建设 2026/9/28 4:46:15

A3144霍尔传感器与LM393比较器实现电机转速测量方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/28 4:46:07

MySQL 5.7 JOIN 连接方式整理

MySQL5.7 原生支持 INNER、LEFT、RIGHT、CROSS、SELF 五种标准 JOIN&#xff1b;不支持直接写 FULL OUTER JOIN&#xff0c;需用 LEFT RIGHT UNION 模拟&#xff1b;另外衍生出左独有、右独有、两表独有三种筛选写法&#xff0c;行业常统称 7 种 JOIN 逻辑。 目录 基础前置测…

作者头像 李华
网站建设 2026/9/28 4:45:52

JVM 思维脑图:一张图吃透 Java 虚拟机核心原理

Java 虚拟机&#xff08;Java Virtual Machine&#xff0c;JVM&#xff09;是 Java 生态中最基础、也最核心的一层基础设施。无论是面试、性能调优、线上故障排查&#xff0c;还是日常写出更高质量的代码&#xff0c;深入理解 JVM 都是绕不开的一步。本文以一张 JVM 思维脑图为…

作者头像 李华
网站建设 2026/9/28 4:45:48

潮州有没有做网站的人?避开5个坑,选对团队省3万块

潮州有没有做网站的人?避开5个坑,选对团队省3万块 在潮州找建站公司,最怕的就是被坑高价,还要承担后续维护的无底洞。很多老板一搜“哪家好”,出来的全是广告,报价从几千到几万不等,心里没底。其实,潮州本地确实有不少靠谱的技术团队,关键在于你如何筛选,如何把控需求,以及如何利用技术手段规避风险。今天我就…

作者头像 李华