【和春笋一起学C++】for语句和递增操作符

目录

1. for语句简介

2. for语句实例

3. 顺序点和副作用

4. 递增递减操作符应用于指针


1. for语句简介

for语句包含控制体循环体,循环体跟在控制体的后面。

如下所示,控制体为for括号中的几个表达式,循环体为花括号中的几条语句

for (initialization; test expression; update-expression)
{语句1;语句2;
}

for语句的执行顺序如下:

  1. 设置初始值;
  2. 执行测试,看看循环是否应当继续进行;
  3. 执行循环操作;
  4. 更新用于测试的值;

初始化,测试和更新操作这三个部分构成了for语句的控制部分,这些操作由括号括起来,其中每一部分都是一个表达式,且彼此由分号隔开。控制体后面的语句叫循环体,只要测试表达式为true,它便执行。

几个注意事项:

  • 控制体只执行一次循环变量的初始化;
  • 循环体中可以包含一条或多条语句;
  • test expression(测试表达式)决定循环体是否被执行,通常,这个表达式是关系表达式,即对两个值进行比较。

2. for语句实例

下面通过一个opencv中图像二值化的实例来更深入的理解for循环,这里主要使用上篇博文《OpenCV中数组和指针运用实例》中的代码,对循环部分稍做了些修改。

#include <iostream>
#include <cstring>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main()
{Mat srcImage = imread("test.jpg");Mat srcGray;cvtColor(srcImage, srcGray, COLOR_BGR2GRAY);Mat outputImage = srcGray.clone();int rows = outputImage.rows;int cols = outputImage.cols*outputImage.channels();int threshold = 50;if (outputImage.isContinuous() == false){cout << "图像数据非连续存储" << endl;return 0;}else{cout << "图像数据为连续存储" << endl;}uchar* data = outputImage.data;int pixels = rows * cols;for (int i = 0; i < pixels; i++){if (*data < threshold){*data++ = 255;}else{*data++ = 0;}}imshow("src", srcImage);imshow("binary", outputImage);waitKey();return 0;
}

对于上面代码中的循环体,前面说过,控制体中i只初始化一次,此处初始化为0。for语句执行流程如下:

                                      

上面图像二值化的代码中难点是for语句的循环体代码的理解,下面我们来逐步分析。

3. 顺序点和副作用

上面流程图中的每一步都是一个完整的表达式,所以更新测试用值这个表达式i++也可以替换成++i,效果是一样的,因为此处的i++和++i都是一个完整表达式,完整表达式末尾有一个顺序点,C++确保副作用在进入循环体之前完成。

副作用定义:副作用(side effect)指的是在计算表达式时对某些东西(如存储在变量中的值)进行了修改。

顺序点定义:顺序点是程序执行过程中的一个点,在这里,在进入下一步之前将确保对所有的副作用都进行了评估。

C++的顺序点有以下两种:

  1. 语句中的分号是一个顺序点,即程序执行下一条语句前,赋值操作符、递增操作符、递减操作符执行的所有修改都必须完成。
  2. 任何完整表达式末尾都有一个顺序点。何为完整表达式?它是一个表达式,但不是另一个更大表达式的子表达式。比如:表达式语句中的表达式部分,for语句控制体中更新测试用值部分,while语句中的检测条件的表达式,if语句的关系表达式部分。

 关于表达式的补充知识:

  1. 对任何表达式加上分号都可以成为一个语句;
  2. C++表达式是一个值,或值与操作符的组合,每个C++表达式都有值;

如10是一个表达式,10+10也是一个表达式,x=10也是一个表达式,它由两个值和一个赋值操作符组成(C++将赋值表达式的值定义为左侧成员的值,所以该表达式的值为20)。


4. 递增递减操作符应用于指针

递增操作符(++)定义:

a++表示使用a的当前值计算表达式,然后将a的值加1;

++a表示先将a的值加1,然后使用新值来计算法表达式;

将递增操作符应用于指针时,将把指针的值增加其指向的数据类型占用的字节数。

int arr[5] = { 21,31,41,51,61 };
int *pt = arr;///使pt指向第一个元素21
++pt;///该语句执行后,pt指向数据第二个元素31

将递增操作符(++)和解除引用操作符(*)结合可以修改指针指向的值。在使用前,需要先了解递增操作符(++)和解除引用操作符(*)的优先级和结合顺序。

前缀递增操作符(即将递增操作符使用在变量前,如++pt)和解除引用操作符的优先级相同,以从右向左的方式进行结合。后缀递增操作符(即将递增操作符使用在变量后,如pt++)的优先级比前缀递增操作符高,即也比解除引用操作符(*)高,并且以从左到右的方式进行结合。

所以以下表达式的含义可以分别解释为:

  1. (*++pt):前缀递增操作符同解除引用操作符相同,结合方向为从右向左,所以该表达式的含义为先将++与pt结合,然后将(*)应用于被递增后的pt。
  2. (++*pt):表示先将(*)与pt结合,然后将pt指向的变量的值加1;
  3.   (*pt)++  :表示先对指针解除引用,然后将解除引用后的变量的值加1;
  4.  *pt++  :因为后缀递增操作符的优先级高于解除引用操作符,所以先将pt与递增操作符(++)结合而不是将(*pt)与递增操作符结合,所以是对指针递增,而不是对指针所指向的变量递增。需要特别注意的是:该语句在执行的时候,是对pt原来的地址解除引用,而不是递增后的新地址解除引用,只有当该语句执行完后pt的值才会指向下一个元素的地址。

上面的话术可能听的云里雾里,结合下面实例看下吧。

#include <iostream>
#include <cstring>
using namespace std;
int main()
{int arr[5] = { 21,31,41,51,61 };int *pt1 = arr;///使pt1指向第一个元素21cout << (*++pt1) << endl;cout << (*pt1) << endl;int *pt2 = arr;cout << (*pt2++) << endl;cout << (*pt2) << endl;return 0;
}

以下是输出结果。

为啥pt1和pt2的输出结果不一致。就是由于递增操作符使用在变量前和变量后的区别,递增操作符使用在指针变量前意味着先使指针变量加1个单位,即先使pt1指向&arr[1],然后再解除引用。递增操作符使用在指针变量后意味着对pt2先解除引用,然后再使pt2指向&arr[1],所以pt2的第一条输出语句输出是21,当该语句执行完后会使pt2指向&arr[1],pt2的第二条输出语句输出值是31。

再回到opencv的二值化实例中的for语句:

for (int i = 0; i < pixels; i++){if (*data < threshold){*data++ = 255;}else{*data++ = 0;}}

现在再来看这条语句*data++ = 255;就好理解了,就是先把data指针原来指向的变量的值赋值为255,然后再使data指针指向下一个元素。如果这条语句变成*++data = 255;那就完全错了,就变成if语句中判断的是当前指向的像素值,而赋值却赋的是下一个像素的值。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/489343.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

有哪些方法可以快速批量的去查询手机号码归属地和运营商,快速的按归属地和运营商进行号码的分类 ?

下面为大家总结了一些快速查询手机号码归属地的工具和方法 工具仅供参考&#xff1a; 如何大批量的进行手机号码归属地查询 &#xff0c;按省份分类&#xff0c;按城市分类&#xff0c;按运营商&#xff08;移动、电信、联通&#xff09;快速分类&#xff0c;高效办公工具批量…

Elasticsearch+Kibana分布式存储引擎

1.ElaticSearch介绍 ElaticSearch &#xff0c;简称为 ES &#xff0c; ES 是一个开源的高扩展的分布式全文检索引擎&#xff0c;它可以近乎实时的存储、检 索数据&#xff1b;本身扩展性很好&#xff0c;可以扩展到上百台服务器&#xff0c;处理 PB 级别的数据。 ES 也使用 …

The Past, Present and Future of Apache Flink

摘要&#xff1a;本文整理自阿里云开源大数据负责人王峰&#xff08;莫问&#xff09;在 Flink Forward Asia 2024上海站主论坛开场的分享&#xff0c;今年正值Flink开源项目诞生的第10周年&#xff0c;借此时机&#xff0c;王峰回顾了Flink在过去10年的发展历程以及 Flink社区…

OpenAI 正式赋予 ChatGPT 通过视频实时与用户互动的能力

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

java jar包加密 jar-protect

介绍 java 本身是开放性极强的语言,代码也容易被反编译,没有语言层面的一些常规保护机制,jar包很容易被反编译和破解。 受classfinal&#xff08;已停止维护&#xff09;设计启发,针对springboot日常项目开发,重新编写安全可靠的jar包加壳加密技术,用于保护软件版权。 使用说…

arm CPS指令解释

arm CPS指令解释 1 The Current Program Status Register, CPSR1.1 N, Z, C, V, bits [31:28]1.2 Q, bit [27]1.3 SSBS, bit [23]1.4 PAN, bit [22]1.4.1 About the PAN bit 1.5 DIT, bit [21]1.6 GE[3:0], bits [19:16]1.7 E, bit [9]1.8 A, I, F, bits [8:6]1.9 M[4:0], bits…

VSCode 报错:rust-analyzer requires glibc >= 2.28 in latest build

报错信息 /home/jake/.vscode-server-insiders/extensions/matklad.rust-analyzer-0.3.953/server/rust-analyzer: /lib/x86_64-linux-gnu/libc.so.6: version GLIBC_2.29 not found (required by /home/jake/.vscode-server-insiders/extensions/matklad.rust-analyzer-0.3.9…

GFPS扩展技术原理(一)消息流

消息流作用 Google fast pair service要求Provider提供一个额外得通道以便seeker寻求建立连接&#xff0c;连接建立后&#xff0c;Seeker就可以向Provider发送一串数据流&#xff0c;这样做的目的是为了支持GFPS Extension&#xff0c;也就是扩展的GFPS&#xff0c;主要涉及一…

Vue项目打包部署到服务器

1. Vue项目打包部署到服务器 1.1. 配置 &#xff08;1&#xff09;修改package.json文件同级目录下的vue.config.js文件。 // vue.config.js module.exports {publicPath: ./, }&#xff08;2&#xff09;检查router下的index.js文件下配置的mode模式。   检查如果模式改…

rk3588-ubuntu22.04系统网关实现路由器功能:

rk3588-ubuntu22.04系统网关实现路由器功能&#xff1a; 场景需求描述&#xff1a; 需求背景&#xff1a; 场景一&#xff1a;通过网线eth0/(路由器wlan0)访问外网&#xff1a; 如果网关 和 设备所处的环境可以通过网线联网或者路由器联网&#xff0c;那么不需要将网关配置成…

GIF制作工具推荐与详细使用教程

引言 GIF&#xff08;Graphics Interchange Format&#xff09;是一种广泛使用的图像格式&#xff0c;常用于创建动画或短视频片段。无论你是想制作表情包、动画教程还是简单的动画效果&#xff0c;选择一个合适的GIF制作工具是关键。下面我们将推荐几款免费且易用的GIF制作工…

打卡第十二天 P1012 [NOIP1998 提高组] 拼数

题目描述 设有 n 个正整数 &#xff0c;将它们联接成一排&#xff0c;相邻数字首尾相接&#xff0c;组成一个最大的整数。 输入格式 第一行有一个整数&#xff0c;表示数字个数 n。 第二行有 n 个整数&#xff0c;表示给出的 n 个整数 。 输出格式 一个正整数&#xff0c…

【每日刷题】Day169

【每日刷题】Day169 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;每日刷题&#x1f34d; &#x1f33c;文章目录&#x1f33c; 1. 718. 最长重复子数组 - 力扣&#xff08;LeetCode&#xff09; 2. 2269. 找到一个数字的 K 美丽值…

SeaTunnel Web1.0.0安装

部署seatunnel2.3.8参考:部署seatunnel2.3.8-CSDN博客 SeaTunnel Web1.0.1对应的seatunnel2.3.3版本,所以如果要想在SeaTunnel Web1.0.1上能正常跑seatunnel对应版本包,在seatunnel上传的connector-开头的包,都得跟着SeaTunnel Web依赖的版本走,如安装了seatunnel2.3.7但…

AI大模型学习笔记|多目标算法梳理、举例

多目标算法学习内容推荐&#xff1a; 1.通俗易懂讲算法-多目标优化-NSGA-II(附代码讲解)_哔哩哔哩_bilibili 2.多目标优化 (python pyomo pareto 最优)_哔哩哔哩_bilibili 学习笔记&#xff1a; 通过网盘分享的文件&#xff1a;多目标算法学习笔记 链接: https://pan.baidu.com…

Go 语言与时间拳击理论下的结对编程:开启高效研发编程之旅

一、引言 结对编程作为一种软件开发方法&#xff0c;在提高代码质量、增强团队协作等方面具有显著优势。而时间拳击理论为结对编程带来了新的思考角度。本文将以 Go 语言为中心&#xff0c;深入探讨时间拳击理论下的结对编程。 在当今软件开发领域&#xff0c;高效的开发方法和…

基于Java的世界时区自动计算及时间生成方法

目录 前言 一、zoneinfo简介 1、zoneinfo是什么 2、zoneinfo有什么 二、在Java中进行时区转换 1、Java与zoneInfo 2、Java展示zoneInfo实例 3、Java获取时区ID 三、Java通过经纬度获取时区 1、通过经度求解偏移 2、通过偏移量计算时间 3、统一的处理算法 四、总结 …

PostgreSQL的学习心得和知识总结(一百六十四)|深入理解PostgreSQL数据库之在 libpq 中支持负载平衡

目录结构 注&#xff1a;提前言明 本文借鉴了以下博主、书籍或网站的内容&#xff0c;其列表如下&#xff1a; 1、参考书籍&#xff1a;《PostgreSQL数据库内核分析》 2、参考书籍&#xff1a;《数据库事务处理的艺术&#xff1a;事务管理与并发控制》 3、PostgreSQL数据库仓库…

BERT:用于语言理解的深度双向 Transformer 的预训练。

文章目录 0. 摘要1. 介绍2. 相关工作2.1 无监督的基于特征的方法2.3 无监督微调方法2.3 从受监督数据中迁移学习 3. BERT3.1 预训练 BERT3.2 微调 BERT 4. 实验4.1 GLUE4.2 SQuAD v1.14.3 SQuAD v2.04.4 SWAG 5. 消融研究5.1 预训练任务的影响5.2 模型大小的影响5.3 使用 BERT …

QT图形/视图架构详解(一)

场景、视图与图形项 图形/视图架构主要由 3 个部分组成&#xff0c;即场景、视图和图形项&#xff0c;三者的关系如图所示&#xff1a; 场景、视图和图形项的关系 场景&#xff08;QGraphicsScene 类&#xff09; 场景不是界面组件&#xff0c;它是不可见的。场景是一个抽象的…