第4章    将语句编织成程序

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

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

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

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

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

4.1.1  用表达式表达设计意图

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

 +  = 

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

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

// 定义需要用到的变量
int a,b,c;
// a、5是操作数,=是操作符,它描述的是一个赋值运算:将常数5赋值给变量a
a = ;
// b、a、5是操作数,=、+都是操作符
// 它描述的计算过程是:先计算变量a和常数5的和,然后将其赋值给变量b
b = a + ;
// 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这两个操作数进行加法运算,表达式的值为3
* ; // 对4和5这两个操作数进行乘法运算,表达式的值为20
% ; // 对10除以7取余,表达式的值为3

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

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

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

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

int a = ;    // 定义整型变量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 = ;
int b = a++ + ; // 变量b的值到底是2还是3呢?

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

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

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

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

4.1.3  赋值操作符

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

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

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

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

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

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

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

你好,C++(16)用表达式表达我们的设计意图——4.1 用操作符对数据进行运算的更多相关文章

  1. 16个时髦的扁平化设计的 HTML5 & CSS3 网站模板

    创建网站最好办法之一是使用现成的网站模板或使用开源 CMS 应用程序.所以,今天这篇文章给大家带来的是16款基于 HTML5 & CSS3 的精美的扁平风格网站模板,大家可以借助这些优秀的网站 ...

  2. 你好,C++(12)怎样管理多个类型同样性质同样的数据?3.6 数组

    3.6  数组 学过前面的基本数据类型之后,我们如今能够定义单个变量来表示单个的数据.比如,我们能够用int类型定义变量来表示公交车的216路:能够用float类型定义变量来表示西红柿3.5元一斤. ...

  3. 你好,C++(12)如何管理多个类型相同性质相同的数据?3.6 数组

    3.6  数组 学过前面的基本数据类型之后,我们现在可以定义单个变量来表示单个的数据.例如,我们可以用int类型定义变量来表示公交车的216路:可以用float类型定义变量来表示西红柿3.5元一斤.但 ...

  4. 立即表达式的多种写法与注意点以及in操作符的作用

    立即表达式,在javascript中非常常见, 采用立即表达式可以形成一个局部作用域, 常配合闭包实现模块化编程等其他用途,接下来我们看看,在大多数的框架中,立即表达式都有哪些写法,以及需要注意的点, ...

  5. 10月16日上午MySQL数据库作业设计表解析

    作业设计表:多张表存储学生成绩及各种信息 需要从表里面体现: 关于学生的:代号 姓名 性别 年龄 班级 关于课程的:代号 名称 关于老师的:代号 姓名 关于成绩的:例如:闫超--网页--90 要能查看 ...

  6. OC--编码建议

      原文 http://www.cocoachina.com/ios/20151118/14242.html   本文是投稿文章,作者: IOS_Tips(微信公众号) “神在细节之中” Object ...

  7. Objective-C 编码建议

    Objective-C 是 C 语言的扩展,增加了动态类型和面对对象的特性.它被设计成具有易读易用的,支持复杂的面向对象设计的编程语言.它是 Mac OS X 以及 iPhone 的主要开发语言. C ...

  8. IOS-OC 编码建议

    “神在细节之中” Objective-C 是 C 语言的扩展,增加了动态类型和面对对象的特性.它被设计成具有易读易用的,支持复杂的面向对象设计的编程语言.它是 Mac OS X 以及 iPhone 的 ...

  9. 基础篇:3.2)规范化:3d零件建模

    本章目的:规范化零件建模,这是机械的基本功夫. 1.建模的总体原则和总体要求 1.1 建模总体原则 a)零件模型应能准确表达零件的设计信息:b)零件模型包含零件的几何要素.约束要素和工程要素:c)零件 ...

随机推荐

  1. 2、vs2012无法从模型更新到数据库的问题

    在模型设计视图空白处选择“从模型生成到数据库…”:不出意外的话应该是打开生成的脚本,当然也可能出现如下的错误,请下载最新的SQL Server Data Tool(我本地VS2012,数据库SQLSe ...

  2. Android HttpClient POST JSON Restful-web-services

    @Override protected String doInBackground(String... arg0) { Gson gson = new Gson(); String json = gs ...

  3. Facebook 开源三款图像识别人工智能软件

    Facebook今天开源了三款人工智能图像分割(Image Segmentation)软件,分别是DeepMask.SharpMask和MultiPathNet,三款工具相互配合完成一个完整的图像识别 ...

  4. Configure swagger with spring boot

    If you haven’t starting working with spring boot yet, you will quickly find that it pulls out all th ...

  5. opencv 用户文档 错误更正 仿射变换

    今天在看opencv官方给出的仿射变换计算仿射变换矩阵的文档的时候,发现官方文档中有个很明显的错误,再次给大家提个醒. 官方文档连接: http://opencv.willowgarage.com/d ...

  6. BestCoder Round #49

    呵呵哒,1001的dfs返回值写错,wa了两发就没分了,1002显然是PAM可是我没学过啊!!!压位暴力可不可以...看看范围貌似不行,弃疗...1003根本不会做,1004想了想lcc发现不可做,那 ...

  7. -_-#【Mac】快捷操作

    快捷键 command + 拖拽 = 剪切option + 拖拽 = 复制command + option + 拖拽 = 快捷方式 command + ] 前进command + [ 后退 comma ...

  8. 【转】Unable to execute dex: Java heap space 解决方案(如何为eclipse.int 添加内存)

    原文网址:http://blog.csdn.net/zengyangtech/article/details/7003379 欢迎转载,转载请注明 http://blog.csdn.net/zengy ...

  9. 【博弈论】HDU 5754 Life Winner Bo

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5754 题目大意: 4种棋子,象棋中的 1王,2车,3马,4后,选其一,B和G轮流走,不能往左上走,一 ...

  10. 酷派D530刷机指引之官方ROM

    刷机前的准备工作 刷官方ROM的大致过程就是:先手机连接电脑,然后在电脑上运行刷机工具,然后那个刷机工具就会把你选择的ROM装到手机里面,然后就没有然后了. 所以在刷机之前,硬件方面需要准备好: 充满 ...