return 0;
}
3.6 关系运算和逻辑运算
往往要求根据某个指定的条件是否满足来决定执行的内容。例如,购物在1000元以下的打九五折,1000元及以上的打九折。C++提供if语句来实现这种条件选择。如
if amount<1000 tax=0.95; //amount代表购物总额,tax代表折扣
else tax=0.9; //若amount<1000,条件满足,tax=0.95,否则tax=0.9
pay=amount*tax; //pay为实付款
3.6.1 关系运算和关系表达式
3.6.2 逻辑常量和逻辑变量
C语言没有提供逻辑型数据,关系表达式的值(真或假)分别用数值1和0代表。C++增加了逻辑型数据。逻辑型常量只有两个,即false(假)和true(真)。
逻辑型变量要用类型标识符bool来定义,它的值只能是true和false之一。如
bool found,flag=false; //定义逻辑变量found和flag,并使flag的初值为false
found=true; //将逻辑常量true赋给逻辑变量found
由于逻辑变量是用关键字bool来定义的,因此又称为布尔变量。逻辑型常量又称为布尔常量。所谓逻辑型,就是布尔型。
3.6.3 逻辑运算和逻辑表达式
有时只用一个关系表达式还不能正确表示所指定的条件。C++提供3种逻辑运算符:
(1) && 逻辑与 (相当于其他语言中的AND)
(2) || 逻辑或 (相当于其他语言中的OR)
(3) ! 逻辑非 (相当于其他语言中的NOT)
逻辑运算举例如下:
a && b 若a,b为真,则a && b为真。
a||b 若a,b之一为真,则a||b为真。
!a 若a为真,则!a为假。
在一个逻辑表达式中如果包含多个逻辑运算符,按以下的优先次序:
(1) !(非)→ &&(与)→ (或),即“!”为三者中最高的。
(2) 逻辑运算符中的“&&”和“||”低于关系运算符,“!”高于算术运算符。
例如:
(a>b) && (x>y) 可写成 a>b && x>y
(a==b) || (x==y) 可写成 a==b || x==y
(!a) || (a>b) 可写成 !a || a>b
将两个关系表达式用逻辑运算符连接起来就成为一个逻辑表达式,上面几个式子就是逻辑表达式。逻辑表达式的一般形式可以表示为
表达式 逻辑运算符 表达式
逻辑表达式的值是一个逻辑量“真”或“假”。前面已说明,在给出逻辑运算结果时,以数值1代表“真”,以0代表“假”,但在判断一个逻辑量是否为“真”时,采取的标准是: 如果其值是0就认为是“假”,如果其值是非0就认为是“真”。例如:
(1) 若a=4,则!a的值为0。因为a的值为非0,被认作“真”,对它进行“非”运算,得“假”,“假”以0代表。
(2) 若a=4,b=5,则a && b的值为1。因为a和b均为非0,被认为是“真” 。
(3) a,b值同前,a-b||a+b的值为1。因为a-b和a+b的值都为非零值。
(4) a,b值同前,!a || b的值为1。
(5) 4 && 0 || 2 的值为1。
在C++中,整型数据可以出现在逻辑表达式中,在进行逻辑运算时,根据整型数据的值是0或非0,把它作为逻辑量假或真,然后参加逻辑运算。
通过这几个例子可以看出: 逻辑运算结果不是0就是1,不可能是其他数值。而在逻辑表达式中作为参加逻辑运算的运算对象可以是0(“假”)或任何非0的数值(按“真”对待)。如果在一个表达式中的不同位置上出现数值,应区分哪些是作为数值运算或关系运算的对象,哪些作为逻辑运算的对象。
实际上,逻辑运算符两侧的表达式不但可以是关系表达式或整数(0和非0),也可以是任何类型的数据,如字符型、浮点型或指针型等。系统最终以0和非0来判定它们属于“真”或“假”。例如′c ′ && ′d′的值为1。
可以将表3.2改写成书中表3.3形式。
熟练掌握C++的关系运算符和逻辑运算符后,可以巧妙地用一个逻辑表达式来表示一个复杂的条件。例如,要判别某一年(year)是否为闰年。闰年的条件是符合下面两者之一: ①能被4整除,但不能被100整除。②能被100整除,又能被400整除。例如2004、 2000年是闰年,2005、 2100年不是闰年。
可以用一个逻辑表达式来表示:
(year % 4 == 0 && year % 100 != 0) || year % 400 == 0
当给定year为某一整数值时,如果上述表达式值为真(1),则year为闰年;否则year为非闰年。可以加一个“!”用来判别非闰年:
!((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
若表达式值为真(1),year为非闰年。也可以用下面的逻辑表达式判别非闰年:
(year % 4 != 0) || (year % 100 == 0 && year % 400 !=0)
若表达式值为真,year为非闰年。请注意表达式中右面的括号内的不同运算符(%,!,&&,==)的运算优先次序。
3.7 选择结构和if语句
if语句是用来判定所给定的条件是否满足,根据判定的结果(真或假)决定执行给出的两种操作之一。
3.7.1 if语句的3种形式
1. if(表达式)语句
例如:if(x>y) cout<
2. if(表达式)语句1 else 语句2
例如:if (x>y) cout<
3. if(表达式1) 语句1
else if(表达式2) 语句2
else if(表达式3) 语句3
…
else if(表达式m) 语句m
else 语句n流程图见图3.6。
例如:
if (number>500) cost=0.15;
else if(number>300) cost=0.10;
else if(number>100) cost=0.075;
else if(number>50) cost=0.05;
else cost=0;
说明:
(1) 从图3.5和图3.6可以看到: 3种形式的if语句都是由一个入口进来,经过对“表达式”的判断,分别执行相应的语句,最后归到一个共同的出口。这种形式的程序结构称为选择结构。在C++中if语句是实现选择结构主要的语句。
(2) 3种形式的if语句中在if后面都有一个用括号括起来的表达式,它是程序编写者要求程序判断的“条件”,一般是逻辑表达式或关系表达式。
(3) 第2、第3种形式的if语句中,在每个else前面有一分号,整个语句结束处有一分号。
(4) 在if和else后面可以只含一个内嵌的操作语句(如上例),也可以有多个操作语句,此时用花括号“{}”将几个语句括起来成为一个复合语句。
例3.6 求三角形的面积。
#include
#include //使用数学函数时要包含头文件cmath
#include //使用I/O流控制符要包含头文件iomanip
using namespace std;
int main( )
{
double a,b,c;
cout<<″please enter a,b,c:″;
cin>>a>>b>>c;
if (a+b>c && b+c>a && c+a>b)
{ //复合语句开始
double s,area; //在复合语句内定义变量
s=(a+b+c)/2;
area=sqrt(s*(s-a)*(s-b)*(s-c));
cout<
cout<<″area=″<
} //复合语句结束
else cout<<″it is not a trilateral!″<
return 0;
}
运行情况如下:
please enter a,b,c:2.45 3.67 4.89↙
area=4.3565
变量s和area只在复合语句内用得到,因此在复合语句内定义,它的作用范围为从定义变量开始到复合语句结束。如果在复合语句外使用s和area,则会在编译时出错,系统认为这两个变量未经定义。将某些变量局限在某一范围内,与外界隔离,可以避免在其他地方被误调用。
3.7.2 if语句的嵌套
3.8 条件运算符和条件表达式
若在if语句中,当被判别的表达式的值为“真”或“假”时,都执行一个赋值语句且给同一个变量赋值时,可以用简单的条件运算符来处理。例如,若有以下if语句:
if (a>b) max=a;
else max=b;
可以用条件运算符(? :)来处理:
max=(a>b)?a:b;
其中“(a>b)?a:b”是一个“条件表达式”。它是这样执行的:如果(a>b)条件为真,则条件表达式的值就取“?”后面的值,即条件表达式的值为a,否则条件表达式的值为“:”后面的值,即b。
条件运算符要求有3个操作对象,称三目(元)运算符,它是C++中惟一的一个三目运算符。条件表达式的一般形式为
表达式1 ? 表达式2 ∶表达式3
条件运算符的执行顺序是:先求解表达式1,若为非0(真)则求解表达式2,此时表达式2的值就作为整个条件表达式的值。若表达式1的值为0(假),则求解表达式3,表达式3的值就是整个条件表达式的值。“max=(a>b)?a:b” 的执行结果是将条件表达式的值赋给max。也就是将a和b二者中的大者赋给max。条件运算符优先于赋值运算符,因此上面赋值表达式的求解过程是先求解条件表达式,再将它的值赋给max。
条件表达式中,表达式1的类型可以与表达式2和表达式3的类型不同。如
x? ′a′∶′b′
如果已定义x为整型变量,若x=0,则条件表达式的值为字符′b′的ASCII码。表达式2和表达式3的类型也可以不同,此时条件表达式的值的类型为二者中较高的类型。如有条件表达式x>y?1:1.5,如果x≤y,则条件表达式的值为1.5,若x>y,值应为1,由于C++把1.5按双精度数处理,双精度的类型比整型高,因此,将1转换成双精度数,以此作为表达式的值。
例3.7 输入一个字符,判别它是否为大写字母,如果是,将它转换成小写字母;如果不是,不转换。然后输出最后得到的字符。
#include
using namespace std;
int main( )
{
char ch;
cin>>ch;
ch=(ch>=′A′ && ch<=′Z′)?(ch+32):ch; //判别ch是否大写字母,是则转换
cout<
return 0;
}
3.9 多分支选择结构和switch 语句
switch语句是多分支选择语句,用来实现多分支选择结构。它的一般形式如下:
switch(表达式)
{case 常量表达式1:语句1
case 常量表达式2:语句2
...
case 常量表达式n:语句n
default:语句n+1
}
例如,要求按照考试成绩的等级打印出百分制分数段,可以用switch语句实现:
switch(grade)
{case ′A′: cout<<″85~100\n″;
case ′B′: cout<<″70~84\n″;
case ′C′: cout<<″60~69\n″;
case ′D′: cout<<″<60\n″;
default : cout<<″error\n″;
}
3.10 编写选择结构的程序
例3.8 编写程序,判断某一年是否为闰年。
#include
using namespace std;
int main( )
{ int year;
bool leap;
cout<<″please enter year:″; //输出提示
cin>>year; //输入年份
if (year%4==0) //年份能被4整除
{if(year%100==0) //年份能被4整除又能被100整除
{if (year%400==0) //年份能被4整除又能被400整除
leap=true; //闰年,令leap=true(真)
else leap=false;} //非闰年,令leap=false(假)
else //年份能被4整除但不能被100整除肯定是闰年
leap=true;} //是闰年,令leap=true
else //年份不能被4整除肯定不是闰年
leap=false; //若为非闰年,令leap=false
if (leap)
cout<
else
cout<
cout<<″ a leap year.″<
return 0;
}
运行情况如下:
① 2005↙
2005 is not a leap year.
② 1900↙
1900 is npt a leap year.
也可以将程序中第8~16行改写成以下的if语句:
if(year%4!=0)
leap=false;
else if(year%100!=0)
leap=true;
else if(year%400!=0)
leap=false;
else
leap=true;
也可以用一个逻辑表达式包含所有的闰年条件,将上述if语句用下面的if语句代替:
if((year%4 == 0 && year%100 !=0) || (year%400 == 0)) leap=true;
else leap=false;
例3.9 运输公司对用户计算运费。路程(s)越远,每公里运费越低。标准如下:
s<250km 没有折扣
250≤s<500 2%折扣
500≤s<1000 5%折扣
1000≤s<2000 8%折扣
2000≤s<3000 10%折扣
3000≤s 15%折扣
设每公里每吨货物的基本运费为p(price的缩写),货物重为w(wright的缩写),距离为s,折扣为d(discount的缩写),则总运费f(freight的缩写)的计算公式为
f = p * w * s * (1 - d)
据此写出程序如下:
#include
using namespace std;
int main( )
{int c,s;
float p,w,d,f;
cout<<″please enter p,w,s:″;
cin>>p>>w>>s;
if(s>=3000) c=12;
else c=s/250;
switch (c)
{ case 0:d=0;break;
case 1:d=2;break;
case 2:
case 3:d=5;break;
case 4:
case 5:
case 6:
case 7:d=8;break;
case 8:
case 9:
case 10:
case 11:d=10;break;
case 12:d=15;break;
}
f=p*w*s*(1-d/100.0);
cout<<″freight=″<
return 0;
}
运行情况如下:
please enter p,w,s:100 20 300↙
freight=588000
3.11 循环结构和循环语句
在人们所要处理的问题中常常遇到需要反复执行某一操作的情况。这就需要用到循环控制。许多应用程序都包含循环。顺序结构、选择结构和循环结构是结构化程序设计的3种基本结构,是各种复杂程序的基本构造单元。因此程序设计者必须熟练掌握选择结构和循环结构的概念及使用方法。
3.11.1 用while语句构成循环
while语句的一般形式如下:while (表达式) 语句
其作用是: 当指定的条件为真(表达式为非0)时,执行while语句中的内嵌语句。其特点是:先判断表达式,后执行语句。while循环称为当型循环。
例3.10 求1+2+3+…+100。
用流程图表示算法,见图3.10。
根据流程图写出程序:
#include
using namespace std;
int main( )
{int i=1,sum=0;
while (i<=100)
{ sum=sum+i;
i++;
}
cout<<″sum=″<
}
运行结果为
sum=5050
需要注意:
(1) 循环体如果包含一个以上的语句,应该用花括号括起来,以复合语句形式出现。如果不加花括号,则while语句的范围只到while后面第一个分号处。
(2) 在循环体中应有使循环趋向于结束的语句。
3.11.2 用do-while语句构成循环
do-while语句的特点是先执行循环体,然后判断循环条件是否成立。其一般形式为
do
语句
while (表达式);
它是这样执行的:先执行一次指定的语句(即循环体),然后判别表达式,当表达式的值为非零(“真”) 时,返回重新执行循环体语句,如此反复,直到表达式的值等于0为止,此时循环结束。
例3.11 用do-while语句求1+2+3+…+100。
#include
using namespace std;
int main( )
{int i=1,sum=0;
do
{ sum=sum+i;
i++;
}while (i<=100);
cout<<″sum=″<
return 0;
}
3.11.3 用for语句构成循环
C++中的for语句使用最为广泛和灵活,不仅可以用于循环次数已经确定的情况,而且可以用于循环次数不确定而只给出循环结束条件的情况,它完全可以代替while语句。
for语句的一般格式为for(表达式1;表达式2;表达式3) 语句
for语句最简单的形式也是最容易理解的格式如下:
for(循环变量赋初值;循环条件;循环变量增值) 语句
例如
for(i=1;i<=100;i++) sum=sum+i;
它的执行过程与图3.10完全一样。它相当于以下语句:
i=1;
while(i<=100)
{sum=sum+i;
i++;
}
显然,用for语句简单、方便。
3.12 break语句和continue语句
break语句的一般格式为
break;
其作用为使流程从循环体内跳出循环体,即提前结束循环,接着执行循环体下面的语句。break语句只能用于循环语句和switch语句内,不能单独使用或用于其他语句中。
continue语句的一般格式为
continue;
其作用为结束本次循环,即跳过循环体中下面尚未执行的语句,接着进行下一次是否执行循环的判定。
continue语句和break语句的区别是:continue语句只结束本次循环,而不是终止整个循环的执行。而break语句则是结束整个循环过程,不再判断执行循环的条件是否成立。如果有以下两个循环结构:
(1)
while(表达式1)
{┆
if(表达式2)break
┆
}
(2)
while(表达式1 )
{┆
if(表达式2) continue;
┆
}
3.13 编写循环结构的程序
例3.12 用下面公式求π的近似值。π/4≈1-1/3+1/5-1/7+…直到最后一项的绝对值小于10-7为止。
根据给定的算法很容易编写程序如下:
#include
#include
#include
using namespace std;
int main( )
{int s=1;
double n=1,t=1,pi=0;
while((fabs(t))>1e-7)
{pi=pi+t;
n=n+2;
s=-s;
t=s/n;
}
pi=pi*4;
cout<<″pi=″<
return 0;
}
运行结果为
pi=3.141592
注意: 不要把n定义为整型变量,否则在执行“t=s/n;”时,得到t的值为0(原因是两个整数相除)。
例3.13 求Fibonacci数列前40个数。这个数列有如下特点:第1、2个数为1、1。从第3个数开始,每个数是其前面两个数之和。即
F1=1 (n=1)
F2=1 (n=2)
Fn=Fn-1+Fn-2 (n≥3)
这是一个有趣的古典数学问题:有一对兔子,从出生后第3个月起每个月都生一对兔子。小兔子长到第3个月后每个月又生一对兔子。假设所有兔子都不死,问每个月的兔子总数为多少?
可以从书中表3.4看出兔子数的规律。
根据给出的每月兔子总数的关系,可编写程序如下:
#include
#include
using namespace std;
int main( )
{long f1,f2;
int i;
f1=f2=1;
for(i=1;i<=20;i++)
{cout<
//设备输出字段宽度为12,每次输出两个数
if(i%2==0) cout<
//每输出完4个数后换行,使每行输出4个数
f1=f1+f2;
//左边的f1代表第3个数,是第1、2个数之和
f2=f2+f1;
//左边的f2代表第4个数,是第2、3个数之和
}
return 0;
}
例3.14 找出100~200间的全部素数。
编写程序如下:
#include
#include
#include
using namespace std;
int main( )
{int m,k,i,n=0;
bool prime; //定义布尔变量prime
for(m=101;m<=200;m=m+2) //判别m是否为素数,m由101变化到200,增量为2
{prime=true; //循环开始时设prime为真,即先认为m为素数
k=int(sqrt(m)); //用k代表根号m的整数部分
for(i=2;i<=k;i++) //此循环作用是将m被2~根号m除,检查是否能整除
if(m%i==0) //如果能整除,表示m不是素数
{ prime=false; //使prime变为假
break; //终止执行本循环
}
if (prime) //如果m为素数
{cout<
n=n+1; //n用来累计输出素数的个数
}
if(n%10==0) cout<
}
cout<
return 0;
}
程序如下:
#include
using namespace std;
int main( )
{char c;
while ((c=getchar( ))!=′\n′)
{if((c>=′a′ && c<=′z′) || (c>=′A′ && c<=′Z′))
{c=c+4;
if(c>′Z′ && c<=′Z′+4 || c>′z′) c=c-26;
}
cout<
}
cout<
return 0;
}
运行结果如下:
I am going to Beijing!↙
M eq ksmrk xs Fimnmrk!
while语句中括号内的表达式有3个作用: ①从键盘读入一个字符,这是用getchar函数实现的; ②将读入的字符赋给字符变量c; ③判别这个字符是否为′\n′(即换行符)。如果是换行符就执行while语句中的复合语句(即花括号内的语句),对输入的非换行符的字符进行转换处理。
按前面分析的思路对输入的字符进行处理。有一点请读者注意:内嵌的if语句不能写成
if (c>′Z′|| c>′z′) c=c-26;
因为所有小写字母都满足“c>′Z′”条件,从而也执行“c=c-26;”语句,这就会出错。因此必须限制其范围为“c>′Z′ && c<=′Z′+4”,即原字母为′W′到′Z′,在此范围以外的不是原大写字母W~Z,不应按此规律转换。请考虑:为什么对小写字母不按此处理,即写成c>′z′ && c<=′z′+4而只须写成“c>′z′”即可。