你好,C++(14)用表达式表达我们的设计意图——4.1 用操作符对数据进行运算

第4章 将语句编织成程序

学过C++中的各种数据类型, 就知道如何使用各种数据类型定义变量来描述现实世界中的各种事物了。现在,我们可以将一个工资统计程序大致写成下面这个样子:


 

// 工资统计程序
int main()
{// 表示员工个数的常量NUMconst int NUM = 100000;// 保存所有工资的数组int arrSalary[NUM];// 保存平均工资的变量float fSalaryAver = 0.0;   // 对工资进行处理…return 0;
}

但是,我们现在只是知道如何用数据类型定义变量来表示现实世界中的数据,而对于如何处理这些数据以解决问题还一无所知。我们不知道如何方便地输入这100000个工资数据,更不知道如何计算这100000个工资数据的平均工资。程序的两个任务——描述数据和处理数据。现在我们已经完成了第一个任务,用各种类型的变量描述现实世界中的数据。那么接下来,我们就看看在C++中如何完成第二个任务——处理数据,从而获得结果数据最终解决问题。

4.1 用运算符对数据进行运算

对数据的处理最常见的就是对数据进行运算,以获得某个运算结果。就像在现实世界中,我们对1和2 进行加法运算,可以得到运算结果3一样,在C++中,我们同样可以用两个int类型的变量a和b来表示1和2,那么,又如何对a和b进行加法运算得到结果数据3呢?

4.1.1 用表达式表达设计意图

在计算数学题的时候,如果想知道两个数的和,总是先用加法运算符号“+”连接两个加数列出加法算式,然后再计算整个算式得到最终的和值。例如:

1 + 2 = 3

在C++中也是如此,如果想对数据进行处理获得运算结果,就要用一个式子将数据的运算处理过程描述出来,因为这个式子表达了我们对这些数据的处理意图,所以这个式子也被称为表达式。而程序在执行计算一个表达式的时候,会按照这个表达式所描述的运算过程对数据进行运算,最终获得整个表达式的运算结果。

在C++中,一个表达式由操作符、操作数和标点符号(必须是英文的)三部分组成,其作用是描述一个对数据的运算过程。表达式的核心是操作符和操作数。操作数就是要参与运算的数据,它可以是变量表示的数据,也可以是直接表示的常数。而连接这些操作数表达运算意图的各种符号就是操作符了,比如表示加法运算意图的“+”,表示乘法运算意图的“*”等。操作数是操作符的处理对象,而操作符则表达了对所连接的操作数的处理方式。比如,一个加法运算表达式“a + 5”中,变量“a”和常数“5”是这个表达式的操作数,而连接这两个操作数的是加法运算操作符“+”,表示将它所连接的两个操作数“a”和“5”进行加和运算得到结果。如果这个表达式是某个更复杂表达式的一部分,那么这个结果将作为这个表达式的值,继续参与运算,直到最终得出整个表达式的值。例如:


 

// 定义需要用到的变量
int a,b,c;
// a、5是操作数,=是操作符,它描述的是一个赋值运算:将常数5赋值给变量a
a = 5;      
// b、a、5是操作数,=、+都是操作符
// 它描述的计算过程是:先计算变量a和常数5的和,然后将其赋值给变量b
b = a + 5;  
// a、b、c是操作数,=、*、-是操作符,()是标点符号
// 它描述的计算过程是:首先计算变量b和变量a的差,然后将其与变量a相乘计算积,
// 最后将积赋值给变量c。运算过程如图4-1所示。
c = a * (b - a);

图4-1 表达式的计算过程

表达式中的操作符决定了整个表达式中操作数的个数。大多数操作符需要两个操作数,比如加法操作符“+”,就需要一个加数和一个被加数。这种需要两个操作数的操作符称为二元操作符,如常见的加、减、乘、除操作符。另外一些操作符需要一个或者三个操作数,相应地被分别称为一元操作符和三元操作符。C++提供了丰富的操作符,用于表达数据之间复杂的运算关系,如有表示加、减、乘、除的算术操作符,也有表示大小关系的关系操作符等。下面就来分别了解一下如何运用这些操作符以实现对数据的处理。

4.1.2 算术操作符

在开发实践中,用得最多的就是用于数学计算的算术操作符了。C++提供的算术操作符有以下几种。

l +(加):计算两个数的和。

l “-”(减):计算两个数的差。

l “*”:(乘):计算两个数的积。

l /(除):计算两个数的商。

l %(取余):计算两个数的余。

以上算术操作符跟数学中相应运算符的用法相同,意义也是一致的。运用这些算术操作符可以很方便地表达对数据的算术运算。例如:

1 + 2;    // 对1和2这两个操作数进行加法运算,表达式的值为3
4 * 5;    // 对4和5这两个操作数进行乘法运算,表达式的值为20
10 % 7;   // 对10除以7取余,表达式的值为3

另外,C++程序中对数值数据的加1或减1操作非常普遍,为了提高编码效率,C++还提供了可以快捷完成此操作的“++(自增)”和“--(自减)”操作符。它们都是一元操作符,可以放在单个操作数的前面或后面(相应地,分别被称为前置操作符或后置操作符),执行对操作数的加1 或减1操作。例如,我们通常用它来实现一些递增和递减的操作:

int nIndex = 0;
// …
// nIndex自身加1,其值递增为1,等同于nIndex = nIndex + 1
++nIndex;

最佳实践:使用前置自增操作符代替后置自增操作符

虽然前置和后置自增操作符的意义是相同的,都是对操作数进行加1操作,但当这两种操作符的结果要继续用来参与运算时,它们的效果却是不一样的。观察下面这段代码:

int a = 1;    // 定义整型变量a,并给a赋初始值为1
cout<<++a;    // 利用前置的自增操作符对a加1,输出为2,这时a的值为2
cout<<a++;    // 利用后置的自增操作符对a加1,输出还是2,但是a的值为3

第二条语句的输出为2,这是因为当使用前置自增操作符时,a首先进行自增运算,其数值变为2,然后再输出a的值,自然就是2了。但是大家一定会对第三句输出也为2感到奇怪,为什么a同样执行了自增操作,输出还是2呢?这是因为使用了后置自增操作符,输出语句首先要输出a的当前值2,然后a再进行自增运算,其值变为3。前置操作符是先计算后输出,后置操作符却是先输出后计算,计算顺序的不同才导致了这么奇怪的结果。

既然它们这么容易让人产生困惑,那么,在实际运用中,到底该如何选择呢?可以记住这样一条编程经验:使用前置自增操作符代替后置自增操作符。这样做可以带来如下好处:

1. 前置操作符的效率优于后置操作符

在C++底层,后置操作符是通过前置操作符实现的,实质上,使用后置操作符最终使用的还是前置操作符,并且增加了额外的转换消耗。所以,使用前置操作符可以一定程度上提高代码的执行效率。

2. 前置操作符不易使人产生困惑,增加代码的可读性

后置操作符有时会让人丈二和尚摸不着头脑。例如:

int a = 1;
int b = a++ + 1; // 变量b的值到底是2还是3呢?

这段代码执行完成后,b的值是2,而不是3。这是因为这里使用的是后置的自增操作符,它会先把a的当前值1用于计算得到结果2,然后再将其赋值给b并自己增加1变为2。结果虽然简单,可是却难以让人“一眼就看出来”,有时甚至会让人错误地认为结果是3。而如果使用前置操作符,写成:

b = ++a + 1; // 先执行a的自增运算变为2,然后执行加1运算,结果为3

则一眼就可以看出b的值是3,整个代码结果一目了然。

前置的自增操作符可以提高代码的执行效率,同时又增加了代码的可读性,那自然是优先选择使用前置自增操作符了,前置的自减操作符也是同样的道理。

4.1.3 赋值操作符

有了算术操作符,就可以得到各个数据的算术运算结果。但是有了运算结果,还需要把结果保存下来以备后用。而赋值操作符就是用来将结果数据保存到变量的。在C++中,最简单的赋值操作符就是“=”。它是一个二元操作符,其右侧通常是某个常数或表达式,而左侧是某个变量。它的作用就是将右侧的值(如果是表达式,则先计算表达式的值)保存到左侧的变量中,以此实现数据的保存。例如:


 

int a, b, c;
// 将1赋值给变量a,a的值变成1,实现数据1的保存
a = 1;             
// 连续赋值,首先执行“c = 1”表达式,将c赋值为1,
// 然后“c = 1”这个表达式的值为1,继续赋值给b,
// b的值也变为1,继续赋值给a,最后a、b、c都被赋值为1
a = b = c = 1;     
// 先计算“b + 1”表达式的值为2,
// 然后继续将其赋值给a,a的值变成2,实现了表达式计算结果的保存
a = b + 1;         

另外,赋值操作符左侧的变量有时也会参与右侧表达式的运算。这时,将先以左侧变量的当前值参与右侧表达式的运算,然后再将运算结果赋值给左侧变量。例如:

// 先用a的当前值2进行“a+10”的计算,得到结果12
// 然后再将结果数据保存到a,a的值变为12
a = a + 10;
// 先用a的当前值12进行右侧表达式的计算,得到结果24
// 然后再将结果数据保存到a,a的值变为24
a = a * (b + 1);

像这种变量既参与计算又保存结果的赋值操作在C++中非常普遍,为了简化代码,C++还将这些表达式中负责计算的操作符跟赋值操作符结合起来,形成了带计算功能的复合赋值操作符。包括:算术操作符与赋值操作符组合,例如+=、-=、*=、/=、%=;位运算操作符与赋值操作符组合,例如<<=、>>=、&=、^=、|=。

这些复合的赋值操作符同样是二元操作符,它们首先将两侧的操作数按照复合操作符中的算术或位运算操作符进行计算,这时参与计算的是变量的当前值,得到计算结果后再赋值给左侧的操作数,从而在计算的同时完成了赋值,实现了计算和赋值的复合。利用复合赋值操作符,上面的代码就可以简化为:

a += 10;            // 等价于表达式 “a = a + 10”,以此实现对a的递增操作
a *= b + 1;         // 等价于表达式 “a = a * (b + 1)”

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

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

相关文章

1232.缀点成线(Java)

题目描述&#xff1a; 给定一个数组 coordinates &#xff0c;其中 coordinates[i] [x, y] &#xff0c; [x, y] 表示横坐标为 x、纵坐标为 y 的点。请你来判断&#xff0c;这些点是否在该坐标系中属于同一条直线上。 输入&#xff1a; coordinates [[1,2],[2,3],[3,4],[4,5]…

(力扣记录)102. 二叉树的层序遍历

数据结构&#xff1a;树&#x1f332; 时间复杂度&#xff1a;O(n) 空间复杂度&#xff1a;O(n) 代码实现&#xff1a; class Solution:def levelOrder(self, root: Optional[TreeNode]) -> List[List[int]]:if not root: return []res []q [root]while q:curr []for…

机器学习:数据集划分笔记

数据集划分是机器学习中非常关键的步骤&#xff0c;能直接影响模型的训练效果和泛化能力。它的主要目的是为了评估模型对新数据的泛化能力&#xff0c;即模型在未见过的数据上能表现良好。 数据集通常被划分为三个部分&#xff1a;训练集&#xff08;Training set&#xff09;、…

Spring boot整合redisson报错

Spring boot整合redisson报错 org.redisson.client.RedisConnectionException: Unable to connect to Redis server: localhost/127.0.0.1:6379 原因 原因是计算机连接不上redis导致的 解决方案 重启redis 在redis文件目录下打开cmd 1.检查redis是否在运行 redis-cli p…

AutoSAR(基础入门篇)9.5-实验:配置通信

目录 一、为通信创建Ports 二、Data Mapping 三、Task Mapping 四、实验总结 终于到了实验篇了,前面的通信内容大家可能看的有点懵,这里确实没什么好的讲解顺序,所以博主自己也觉得讲的有点乱。但是不要紧,前面讲的通信的内容基本上大家很难用到。特别是对于初学者来说…

问题:实行网络化管理,为此需要做好以下几个方面的工作。() #知识分享#其他#职场发展

问题&#xff1a;实行网络化管理&#xff0c;为此需要做好以下几个方面的工作。() A、建立“公共部门—私人部门—第三部门”的合作网络 B、采用平等协商、双向互动、共同参与的决策方式&#xff0c;参与式决策应当成为网络化管理中的主要决策方式 C、建立“公共部门—私人部…

vue axios 请求后端无法传参问题

vue请求后端无法传参问题 问题描述处理过程总结 问题描述 在学习vue时&#xff0c;使用axios调用后端&#xff0c;发现无法把参数正确传到后端&#xff0c;现象如下&#xff1a; 使用vue发起请求&#xff0c;浏览器上已经有传参&#xff0c;但是后端没接收到对应的用户名密码&…

算法之贪心

1.部分背包问题 代码1&#xff1a; 代码2&#xff1a; 但如果金币不能分割&#xff0c;那贪心就不是最优解&#xff0c;正确的做法是搜索或动态规划。 2.排队接水 3.在规定时间内参加最多的比赛 4.合并果子 使用memset初始化int数组时&#xff0c;第二个参数如果是0&#xff0…

Vue源码系列讲解——模板编译篇【五】(优化阶段)

1. 前言 在前几篇文章中&#xff0c;我们介绍了模板编译流程三大阶段中的第一阶段模板解析阶段&#xff0c;在这一阶段主要做的工作是用解析器将用户所写的模板字符串解析成AST抽象语法树&#xff0c;理论上来讲&#xff0c;有了AST就可直接进入第三阶段生成render函数了。其实…

uniapp 开发一个密码管理app

密码管理app 介绍 最近发现自己的账号密码真的是太多了&#xff0c;各种网站&#xff0c;系统&#xff0c;公司内网的&#xff0c;很多站点在登陆的时候都要重新设置密码或者通过短信或者邮箱重新设置密码&#xff0c;真的很麻烦 所以准备开发一个app用来记录这些站好和密码…

软件风险分类整理

软件项目风险分类整理 1.需求分析 2.软件设计 3.编码和单元测试 4.集成和测试 5.验收和维护 6.团队管理 7.成本管理 8.组织管理

事务及在SpringBoot项目中使用的两种方式

1.事务简介 事务&#xff08;transaction&#xff09;是访问并可能操作各种数据项的一个数据库操作序列&#xff0c;这些操作要么全部执行&#xff0c;要么全部不执行&#xff0c;是一个不可分割的工作单位。 事物的四大特性: 原子性&#xff08;Atomicity&#xff09;&#xf…

ubuntu22.04@laptop OpenCV Get Started: 010_blob_detection

ubuntu22.04laptop OpenCV Get Started: 010_blob_detection 1. 源由2. blob应用Demo2.1 C应用Demo2.2 Python应用Demo 3. 重点分析3.1 Threshold3.2 Area3.3 Circularity3.4 Convexity3.5 Inertia Ratio 4. 总结5. 参考资料6. 补充 1. 源由 Blob是图像中的一组连接像素&#…

Go教程-Go语言简介

这篇文章我们来聊聊Go语言。 Go语言发展历史 以下是Go语言发展的几个里程碑节点&#xff1a; Go一开始是Google内部的一个项目&#xff0c;由三位大佬Rob Pike、Robert Griesemer、Ken Thompson早2007年发起。在2009年11月&#xff0c;Go语言正式对外开源。在2010年&#xf…

Java中的String类的常用方法(对于字符串的常用操作)

目录 一、获取指定索引的字符 二、 获取指定字符或者字符串的索引位置 三、判断字符串是否以指定内容开头或结尾 四、替换指定的字符或者是字符串 五、获取字符串的子串 六、将字符串转换为字符数组 七、比较字符串的内容是否相等 八、连接字符串 九、比较两个字符串的大…

2024-02-16 AIGC-数字人-硅基DUIX-记录

摘要: 2024-02-16 AIGC-数字人-硅基DUIX-记录 文档: https://duix.guiji.ai/duix-website/localHuman Digital Humans (guiji.ai) 文档中心 (guiji.ai) DUIX本地渲染SDK安卓集成文档_v1 | 文档中心 (guiji.ai) 本地化部署duix说明: 将DUIX离线部署到本地并在本地生成数字人需要…

ESP32学习(3)——连接WIFI

1.简介 Wi-Fi是基于IEEE 802.11标准的无线网络技术 让联网设备以无线电波的形式&#xff0c;加入采用TCP/IP通信协议的网络. Wi-Fi设备有两种模式&#xff1a; 1.Access Point(AP) 模式&#xff0c;此为无线接入点&#xff0c;家里的光猫就是结合WiFi和internet路由功能的AP。…

【Java程序员面试专栏 分布式中间件】Redis 核心面试指引

关于Redis部分的核心知识进行一网打尽,包括Redis的基本概念,基本架构,工作流程,存储机制等,通过一篇文章串联面试重点,并且帮助加强日常基础知识的理解,全局思维导图如下所示 基础概念 明确redis的特性、应用场景和数据结构 什么是Redis,Redis有哪些应用场景 Redi…

【十九】【C++】 priority_queue简单使用和仿函数

priority_queue文档介绍翻译 优先队列是一种容器适配器&#xff0c;专门设计成其中的第一个元素始终是根据某种严格的弱排序准则最大的元素。 这种上下文类似于堆&#xff0c;其中元素可以在任何时刻插入&#xff0c;而只能检索最大堆元素&#xff08;在优先队列中顶部的元素&a…

Stable Diffusion系列(五):原理剖析——从文字到图片的神奇魔法(扩散篇)

文章目录 DDPM论文整体原理前向扩散过程反向扩散过程模型训练过程模型生成过程概率分布视角参数模型设置论文结果分析 要想完成SD中从文字到图片的操作&#xff0c;必须要做到两步&#xff0c;第一步是理解文字输入包含的语义&#xff0c;第二步是利用语义引导图片的生成。下面…