【小课堂】三、运算符、表达式、分支结构

C/C++语言提供了一系列实用的运算符以便计算。

算术运算符

有+,-,*,/,%
前面四个是相对熟悉的四则运算,不过这里要提一下的是,由于在C/C++语言中有数据类型的限制,计算的结果是和参与运算的类型有关的:
C++:

1
2
3
4
5
6
7
int a=5,b=2;
float c=a/b;
cout<<"a/b="<<c<<endl;

float d=2;
float e=a/d;
cout<<"a/d="<<e<<endl;

C:

1
2
3
4
5
6
7
int a=5,b=2;
float c=a/b;
printf("a/b=%f\n",c);

float d=2;
float e=a/d;
printf("a/d=%f\n",e);

输出:
a/b=2.000000
a/d=2.500000
由此发现:只有整型运算时,/进行整数除法,有实型参与运算时,将会进行实数除法。
这里的%是取模运算,a%b即求a/b的余数,虽然这个运算平时很少出现,但在离散数学领域,是有很多奇妙效果的,我们将在后续的实践中体验到。

关系运算符

有>,<,>=,<=,==,!=
分别为大于、小于,大于等于,小于等于,等于,不等于
在C/C++语言中,它们用于判断两个量之间的关系,如果成立,结果为1,不成立结果为0。
C++:

1
2
3
4
int a=1,b=2,c=2,d=4;
cout<<"a>b ?"<< a>b <<endl;
cout<<"b==c ?"<< b==c <<endl;
cout<<"c!=d ?"<< c!=d <<endl;

C:

1
2
3
4
int a=1,b=2,c=2,d=4;
printf("a>b ?%d\n",a>b);
printf("b==c ?%d\n",b==c);
printf("c!=d ?%d\n",c!=d);

输出:
a>b ?0
b==c ?1
c!=d ?1
输出显示:a>b的结果为假,b==c的结果为真,c!=d的结果为真。

逻辑运算符

有&&(与),||(或),!(非)三种
分别对应与、或、非三种逻辑。
劳技课认真上的同学应该对这三种最基本的逻辑门不陌生,没认真上的同学也应该对数学中集合的交、并、补这三种运算有了解(笑)。可以说这三种逻辑是人类逻辑的一个原点(也是使现代计算机拥有逻辑能力的唯一实现方法,可参考“现代计算机组成原理”)。
这里本来不打算引入真值表,因为程序设计的逻辑复杂度远没有硬件逻辑门这么深,还是放一下,以便大家参考。
与:
0 0 0
0 1 0
1 0 0
1 1 1
或:
0 0 0
0 1 1
1 0 1
1 1 1
非:
0 1
1 0

布尔型

C++中为布尔(逻辑)运算提供了专门的布尔数据类型

1
2
bool a=true;
bool b=false;

类型名为bool(布尔Boolean的缩写),只有两个值true(真)和false(假),占一个字节。

C++中的布尔量可以进行逻辑运算:

1
2
bool a=true,b=false;
cout<<(a&&b);

输出:
0

可以发现,布尔量a,b之间可以进行逻辑运算。而false/true只是0/1的一个别名。

在C中没有bool类型,一般用整型赋值为0和1来实现。

赋值运算符

是将运算和赋值合并的一种运算。在程序编写中,这一类运算特别常用,C/C++语言也提供了支持:
+=,-=,*=,/=,%=

以下每行等价:

1
2
3
4
5
6
a+=b;a=a+b;
a-=b;a=a-b;
a*=b;a=a*b;
a/=b;a=a/b;
a%=b;a=a%b;

自增运算符

特别的,如果要对一个变量自增、自减1,有以下运算:
++,--
以下每行等价:

1
2
a++;a+=1;a=a+1;
a--;a-=1;a=a-1;

另外,区分以下两表达式:

1
2
3
4
int i=3,x;
x=i++;//x==3
i=3;
x=++i;//x==4

我们发现,自增运算的前缀模式是先加再赋值,后缀模式是先赋值再加。虽然C/C++语言提供了这种灵活性,我们在初学时只需掌握++的后缀形式即可。

运算符的优先级

正如“先乘除、后加减”的运算法则,只有确定了优先级,程序的编写才没有二义性。
从高到低:

*、/、%
+、-
>、<、>=、<=
==、!=
&&、||

以上的每一行中的运算符优先级相同。

虽然C/C++语言还提供了如位运算、三目运算等其他运算符,我们在初学阶段不作要求。

表达式

有了运算符,我可以就可以组成各种表达式。其中,算术运算符组成的表达式称为算术表达式,关系运算符与逻辑运算符组成的叫逻辑表达式。在这里,有同学会有疑问:既有算术又有逻辑的是什么呢,答:看具体结果。
如:

1
2
3
4
5
a+b//算术
a&&b//逻辑
(a==b)||(b==c)//逻辑
(a+b>c)&&(c>0)//逻辑
(a&&b)+(a||c)//算术

(具体涉及原理性的内容可自习:表达式树)
可以发现,逻辑表达式的结果是一个布尔量,如:

1
2
1>0  //结果为true
1>2 //结果为false

正如算术表达式/整型(或实型)变量/常数在代码中可以混合计算,逻辑表达式/布尔变量/布尔常量(true/false)也是一样:

1
2
3
4
5
6
7
int a=10,b=20,c;
bool d=true,e=false,f;
//算术表达式
c=(a+b)*a+5;

//逻辑表达式
f=(d||e)&&(b>a)||(!d);

可以自行计算上式中c和f的值,练习对表达式的理解。
(答案:c=305,f=true)

分支结构

是用计算机帮你思考的第一步。从此以后,程序就不是按照顺序按部就班的执行了,而是依照编写出的一定的规则执行。

if语句

if语句有两种形式:

1
2
3
4
5
6
7
8
9
//1
if(条件)
语句1;

//2
if(条件)
语句1;
else
语句2;

其中的条件指的是一个逻辑表达式。
第一种:如果条件成立,执行语句1,否则不执行(即跳过语句1)。
第二种:如果条件成立,执行语句1,否则执行语句2。

if语句的嵌套

嵌套也是信息学中的重要概念,接下来的很多语句都可以嵌套。

1
2
3
4
5
6
7
if(条件1)
语句1;
else
if(条件2)
语句2;
else
语句3;

我们分析一下这段程序:
这段程序有两个if语句,其中的else中的语句又是一个if语句。整个程序的意思为:如果条件1成立,执行语句1,否则(“否则”中又是一个if语句){如果条件2成立,执行语句2,否则执行语句3}。
这样我们理论上是可以无限嵌套的,程序的逻辑也开始复杂起来。细心的同学会发现上面的代码不同的语句前面有长度不一的空格,这里我们引进概念:缩进。

缩进

缩进是一种让代码更让人一目了然的技巧。比如上面if嵌套的例子:我们把跟在if后面的语句往后推几个空格(一般是4个空格),表示这句语句属于这个if管辖,在else后面的那个if语句也往后几个空格(但要与前面的语句1对齐),表示这个if语句属于这个else,最后,语句二和语句3要比第二个if语句再往后推几个空格,表示从属关系。
我们可以发现,这个规则的目的是让同级别的语句落在同一列上,不同级别的语句错开,这种规则被形象地称为锯齿状,为了增加代码的可读性(就是能一眼就能看懂一段代码在说什么)。
事实上,C/C++语言不对代码的格式进行限制,也就是说如果代码不进行缩进操作也一样能编译运行,那为什么一定要养成缩进的好习惯呢?请看:
C(C++自行改cout):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
if(a>b)
if(b>c)
printf("a,b,c")
else
if(a>c)
printf("a,c,b");
else
printf("c,a,b");
else
if(b<c)
printf("c,b,a");
else
if(a>c)
printf("b,a,c");
else
printf("b,c,a");
……

这是输出三个数大小顺序的代码片段,但是就这么几行,你能很快的读懂他想干什么吗?能很快地答出他编得是否正确?还是已经看晕了?
如果使用缩进:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
if(a>b)
if(b>c)
printf("a,b,c")
else
if(a>c)
printf("a,c,b");
else
printf("c,a,b");
else
if(b<c)
printf("c,b,a");
else
if(a>c)
printf("b,a,c");
else
printf("b,c,a");

将会一目了然。
在初学阶段,程序简单,对格式的重视往往不够,但这对以后的进阶是不利的,我们还是要坚持缩进,多关注教程中其他代码的缩进规范。

语句块

我们又会遇到一个问题:一句if里面要执行多句语句怎么办呢?这里我们引出语句块的使用:

1
2
3
4
5
6
7
8
9
10
11
12
if(条件1){
语句1;
语句2;
……
语句n;
}
else{
语句1;
语句2;
……
语句n;
}

用一个大括号表示,大括号中的所有语句都将从属于一个if(或一个else)。
没错,int main(void){}的大括号也是语句块,表示里面编写的所有语句从属于这个main函数。事实上,C/C++语言中几乎任何用一句语句的场合都可以用语句块代替,实现在同一个条件下执行若干语句的功能。

有了分支结构,我们就可以解决有一定难度的问题了。

作业

思考:

1、什么是运算符?运算符起什么作用?我们为什么要运算符?
2、什么是表达式?什么是布尔量?什么是逻辑运算?
3、什么是分支结构?它实现了哪种功能?
4、什么是嵌套?在自然界/生活中,哪里体现了类似嵌套的思想?
5、什么是缩进?我们为什么要坚持缩进?

习题:

1、键盘输入一个正整数,判断是否能被3整除,能输出YES,不能输出NO
2、水仙花数是指一个三位正整数的各位数字的立方和等于它本身的数。输入一个正整数,判断是否为水仙花数,是输出YES,不是输出NO
3、键盘输入三个正整数,按从大到小顺序输出这三个数。
*4、输入正整数m,n,输出2019年的m月n日是星期几,用0到6表示(0为星期日)。
*5、小玉家的电费