当前位置: 首页 > java >正文

[C/C++安全编程]_[中级]_[如何安全使用循环语句]

场景

  1. 在标准C里,使用循环语句也是有可能造成越界或死循环的,那么在现代C++开发里能避免吗?

说明

  1. C++11标准里,新增了一个范围for循环语句,可以快速枚举集合,数组,并且不需要索引操作。 这个是正向枚举的推荐操作,可以避免越界。
for (const auto& one : array_1)cout << one << endl;
  1. C++98时可以使用<algorithm>算法库的std::for_each来执行枚举,效果等同于使用迭代器枚举。不涉及到索引值操作,可以安全的。
for (auto ite = array_1.begin(); ite != array_1.end(); ++ite) {cout << *ite << endl;
}
  1. 在倒序枚举时,C++也有倒序迭代器可以用,也是安全的。
for (auto ite = array_1.rbegin(); ite != array_1.rend(); ++ite) {cout << *ite << endl;
}
  1. 如果非要在倒序时使用索引值,那么要注意循环变量不要声明为无符号常量。比如size_t就是无符号常量,是集合方法.size()的返回类型。因为无符号常量在递减的时候不会出现小于0的情况。
cout << "=== index 1 type ==" << endl;
for (int i = array_1.size() - 1; i >= 0; --i) {  // 使用后置递减,避免 unsigned 类型的问题cout << "[" << i << "] => " << array_1[i] << endl;
}
  1. 注意1: 使用goto跳出循环需要跳出全部循环,避免逻辑混乱和死循环。
for (auto i = 0; i < 100; ++i) {for (auto j = 0; j < 100; ++j) {if ( i && j && (j % 10 == 0)) {cout << "i: " << i << " j: " << j << endl;goto next;}}
}
next:
  1. 避免修改循环变量,避免逻辑混乱,死循环和越界访问。
for (auto i = 0; i < 100; ++i) {if (i && (i % 5) == 0)i--;
}
  1. 不要使用浮点型作为循环变量,因为浮点型有精度问题,可能会导致条件不成立。

    • 浮点型的值i可能永远不会达到10.0f导致死循环。

    • 浮点型运算比整型慢的多。

    for(auto i = 1.0f; i != 10.0f; i+= 0.1f)
    

例子

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>using namespace std;void TestDecreaseLoop()
{vector<int> array_1 = {4,5,9,2,3,1,0,3,2};// 1. 优先选择: 使用反向迭代器; 不涉及到索引的修改,不会出错。cout << "=== iterator ==" << endl;for (auto ite = array_1.rbegin(); ite != array_1.rend(); ++ite) {cout << *ite << endl;}// 2. 如果需要索引,注意使用`int`声明循环变量,如果使用`auto`,那么会是`size_t`类型;// -- 而`size_t`是无符号整型,不会出现小于`0`的情况。cout << "=== index 1 type ==" << endl;for (int i = array_1.size() - 1; i >= 0; --i) {  // 使用后置递减,避免 unsigned 类型的问题cout << "[" << i << "] => " << array_1[i] << endl;}// 错误:i 一直大于等于`0`,死循环。//for (auto i = array_1.size() - 1; i >= 0; --i) {//	cout << "[" << i << "] => " << array_1[i] << endl;//}// -- 另一种获取索引的方式cout << "=== index 2 type ==" << endl;auto iend = array_1.rend();for (auto ite = array_1.rbegin(); ite != iend; ++ite) {cout << "[" << iend - ite - 1 << "] => " << *ite << endl;}
}void processOne(int& one) 
{cout << one << endl;
}void TestIncreaseLoop()
{vector<int> array_1 = {4,5,9,2,3,1,0,3,2};// 1. 优先使用范围`for`循环,避免使用索引cout << "=== range for ==" << endl;for (const auto& one : array_1)cout << one << endl;// 2. 如果是`C++98`cout << "=== for_each ==" << endl;for_each(array_1.begin(), array_1.end(), processOne);// -- 效果等同于使用`iterator`cout << "=== iterator ==" << endl;for (auto ite = array_1.begin(); ite != array_1.end(); ++ite) {cout << *ite << endl;}// 3. 最后的选择: 需要用到索引时;cout << "=== index ==" << endl;auto size = array_1.size();for (auto i = 0; i < size; ++i) {cout << "[" << i << "] => " << array_1[i] << endl;}
}void TestOtherLoop()
{// 1. 使用`goto`跳出循环需要跳出全部循环,避免逻辑混乱和死循环。for (auto i = 0; i < 100; ++i) {for (auto j = 0; j < 100; ++j) {if ( i && j && (j % 10 == 0)) {cout << "i: " << i << " j: " << j << endl;goto next;}}}next:cout << "loop finish" << endl;// 2. 避免修改循环变量,避免逻辑混乱,死循环和越界访问。//for (auto i = 0; i < 100; ++i) {//	if (i && (i % 5) == 0)//		i--;//}// 3. 不要使用浮点型作为循环变量,因为浮点型有精度问题,可能会导致条件不成立。// -- 浮点型的值`i`可能永远不会达到10.0f导致死循环。// -- 浮点型运算比整型慢的多。// for(auto i = 1.0f; i != 10.0f; i+= 0.1f)
}int main()
{std::cout << "Hello World!\n";cout << "========== TestDecreaseLoop =========" << endl;TestDecreaseLoop();cout << "========== TestIncreaseLoop =========" << endl;TestIncreaseLoop();cout << "========== TestOtherLoop =========" << endl;TestOtherLoop();
}

输出

Hello World!
========== TestDecreaseLoop =========
=== iterator ==
2
3
0
1
3
2
9
5
4
=== index 1 type ==
[8] => 2
[7] => 3
[6] => 0
[5] => 1
[4] => 3
[3] => 2
[2] => 9
[1] => 5
[0] => 4
=== index 2 type ==
[8] => 2
[7] => 3
[6] => 0
[5] => 1
[4] => 3
[3] => 2
[2] => 9
[1] => 5
[0] => 4
========== TestIncreaseLoop =========
=== range for ==
4
5
9
2
3
1
0
3
2
=== for_each ==
4
5
9
2
3
1
0
3
2
=== iterator ==
4
5
9
2
3
1
0
3
2
=== index ==
[0] => 4
[1] => 5
[2] => 9
[3] => 2
[4] => 3
[5] => 1
[6] => 0
[7] => 3
[8] => 2
========== TestOtherLoop =========
i: 1 j: 10
loop finish

参考

  1. C++ Core Guidelines

  2. C++11语言特性和标准库

http://www.xdnf.cn/news/15818.html

相关文章:

  • 语言学校为何成为IT润日路径的制度跳板?签证与迁移结构的工程化拆解
  • 交通出行大前端与 AI 融合:智能导航与出行预测
  • 智能制造——48页毕马威:汽车营销与研发数字化研究【附全文阅读】
  • jxORM--编程指南
  • linux + 宝塔面板 部署 django网站 启动方式:uwsgi 和gunicorn如何选择 ?
  • windows命令提示符cmd使用
  • Django接口自动化平台实现(四)
  • 第 30 场 蓝桥·算法入门赛 题解
  • 制作mac 系统U盘
  • 零基础学习性能测试第一章-为什么会有性能问题
  • 全面解析 JDK 提供的 JVM 诊断与故障处理工具
  • VSCode使用Jupyter完整指南配置机器学习环境
  • 秒赤Haproxy配置算法
  • `TransportService` 是 **Elasticsearch 传输层的“中枢路由器”**
  • SparseTSF:用 1000 个参数进行长序列预测建模
  • RabbitMQ面试精讲 Day 4:Queue属性与消息特性
  • Java拓扑排序:2115 从给定原材料中找到所有可以做出的菜
  • LWJGL教程(2)——游戏循环
  • 网络(HTTP)
  • 【实战1】手写字识别 Pytoch(更新中)
  • 【no vue no bug】 npm : 无法加载文件 D:\software\nodeJS\node22\npm.ps1
  • 嵌入式硬件篇---舵机(示波器)
  • 小架构step系列20:请求和响应的扩展点
  • 解锁Phpenv:轻松搭建PHP集成环境指南
  • 使用“桥接模式“,实现跨平台绘图或多类型消息发送机制
  • 抓包工具使用教程
  • PaliGemma 2-轻量级开放式视觉语言模型
  • 【RocketMQ 生产者和消费者】- 消费者发起消息拉取请求 PullMessageService
  • ps2025下载与安装教程(附安装包) 2025最新版photoshop安装教程
  • 群组功能实现指南:从数据库设计到前后端交互,上班第二周