第2章 类型转换及流程控制
C++是一种通用的程序设计语言,特别适合于面向对象的程序设计。它支持数据抽象,支持面向对象的程序设计和通用性程序设计。面向对象程序设计是一种程序设计技术,是对一组问题编写出“好”程序的一种范例。本章的实例都是入门级的,如各类常量的使用例子,递增(increase)运算符(++)、递减(decrease)运算符(--)和取模运算(%)。
本章重点讲解控制结构,内容包括条件结构if选择、while循环及do-while循环、for循环、switch选择结构。初学者对这些内容应多实践,相互替换,本章还举了综合应用的实例,举一反三对提高编程能力相当重要。
2.1 类型转换
案例2-1 消失的重量
【案例描述】
变量在C++中,类型转换运算符可以就是将一种类型的数据转换为另一种类型的数据。转换中会造成数据达不到精度的情况,如浮点数转换为整数时,那么其值数据只就输出整数部分,也就是取整。本例消失的重量就是取整的结果,如图2-1所示。
图2-1 消失的重量
【实现过程】
程序从首先将输入的整数类型转换成浮点数类型,再从将输入的浮点数和双精度浮点数转换成整数输出。代码如下:
#include <iostream>
#include <iostream.h>
int main()
{
int inputnum0;
float inputnum1; //定义浮点数
double inputnum2; //定义双精度浮点数
std::cout << "输入物体重量(整数,吨):" << std::endl;
std::cin >>inputnum0;
std::cout << "转换成浮点数输出,吨:" <<(float) inputnum0<< std::endl;
std::cout << "输入物体重量(带2位小数,吨):" << std::endl;
std::cin >>inputnum1; //输入浮点数
std::cout << "转换成整数输出,吨:" <<(int) inputnum1<< std::endl;
std::cout << "输入物体重量(带3位小数,吨):" << std::endl;
std::cin >>inputnum2; //输入双精度浮点数
std::cout << "转换成整数输出,吨:" <<int(inputnum2)<< std::endl;
system("pause");
return 0;
}
【案例分析】
(1)从上面的代码可以看到,整数转换成浮点数后,值保持不变,但浮点数和双精度浮点数转换成整数后,其小数点后面的值就去掉了,这就是所谓的取整。变量类型转换运算符可以将一种类型的数据转换为另一种类型的数据。在C++中有几种方法可以实现类型转换这种操作,最常用的一种也是与C兼容的一种,是在原要转换的表达式前面加圆括号括起的新数据类型,如(int) inputnum1,这是比较简单的类型转换。
(2)以后的实例中会提到高级C++类型转换、控制类之间的转换,ANSI-C++标准定义了4种新的类型转换操作符:reinterpret_cast、static_cast、dynamic_cast和const_cast。
提示:实际编程中,经常需要进行数据类型转换。例如,上面的实例中数字类型的转换,以后会用显示显式类型转换。在编程中多实践时,要注意值在转换后与转换前的变化。
案例2-2 游泳池的容量
【案例描述】
实例2-1描述了类型转换,本例仍然是类型转换的实例。,输入的变量类型是double,然后经过计算后输出double和int两种类型,。实例中还会提到数学运算符的优先级问题,。本例效果如图2-2所示。
图2-2 游泳池的容量
【实现过程】
程序(1)定义一个结构体类型 struct Column,;
(2)提示用户输入游泳池的半径和高度;
,(3)按照数学方法计算出游泳池的容量和表面积,然后输出数据类型double和int的结果。
详细代码如下:
#include<iostream.h>
#include<iostream>
const double pi=3.1415926;
struct Column
{
double radius; //半径
double height; //高度
}myc;
void main()
{
double r,h;
double volum; //游泳池的容量
double surface; //游泳池的表面积
int volum1,surface1;
cout<<"输入游泳池的半径和高度";
cout<<endl;
cout<<"radius=";
cin>>r;
cout<<"height=";
cin>>h;
myc.radius=r; //半径和高度的值存储在myc结构
myc.height=h;
volum=pi*myc.radius*myc.radius*myc.height; //计算容量,假设是圆柱型
surface=2*pi*myc.radius*(myc.height+myc.radius); //计算表面积
volum1=pi*myc.radius*myc.radius*myc.height; //① 计算容量,假设是圆柱型
surface1=2*pi*myc.radius*(myc.height+myc.radius); //计算表面积
cout<<"游泳池的容量: "<<volum; //输出计算结果
cout<<"整输出为:"<<volum1;
cout<<"取整输出为:"<<(int)volum;
cout<<endl;
cout<<"游泳池的表面积: "<<surface;
cout<<"整输出为:"<<surface1;
cout<<"取整输出为:"<<(int)surface;
cout<<endl;
system("pause");
}
【案例分析】
(1)①处,经过计算得出结果volum1,右边的变量是double数据类型,volum1计算结果是int数据类型;(int)volum;是实例005提到的double转换成int显式类型转换。这两种计算结果是一样的,都是用浮点数计算,得出的浮点数再取整。
(2)编程中要注意计算的顺序,如2*pi*myc.radius*(myc.height+myc.radius);,先计算()中的,然后从左到右依次执行。在C++中出现的运算符都有优先级,计算顺序是从*到最低级。
提示:编写一个复杂的表达式时,若如果不确定表达式的执行顺序,那么就最好加上括号(),这样还可以使代码更易读懂。
案例2-3 显式转换
【案例描述】
在显式类型转换中,应特别注意从较高级别的类型转换为较低级别的类型时,容易引起数据的丢失,因为不同类型的数据表示的范围不同。本例是显式转换的例子,效果如图2-3所示。
【实现过程】
程序定义了无符号整型变量y,然后把整数500转换为unsigned char后,将转换后的值赋给y。代码如下:
#include <iostream>
using namespace std;
int main()
{
using namespace std;
unsigned int y=unsigned char (500); //显式转换
cout<<"y is "<<y<<endl; //输出显式转换后的值
system("pause");
return 0;
}
【案例分析】
(1)一般情况下,数据的类型转换通常是由编译系统自动进行的,不需要人工干预,所以被称为隐式类型转换。但如果程序要求一定要将某一种类型的数据转换为另外一种类型,则可以利用强制类型转换运算符的方式进行转换,这种强制转换过程方式称为显式转换。
(2)unsigned int y=unsigned char (500)这条语句进行了显式数据转换,会导致数据丢失。unsigned char没有符号位,因此只能表示0~255范围的整数。
提示:不加限制的显式类型转换往往会给程序带来很多安全隐患。
2.2 判断语句
案例2-4 计算年份是否为闰年(各种运算符结合)
【案例描述】
本章开始从基本的C++入门实例讲起,在上一第1章演示了很多数学运算符参与运算的实例,下面这个本实例综合使用这些运算符,要求输入任意一个年份,实现判断是否是闰年,并输出结果。本例效果如图2-4所示。
图2-4 计算年份是否为闰年(各种运算符结合)
【实现过程】
首先定义需要用到的2两个变量,然后提示输入年份,取得年份后判断是否为闰年,提示是否继续,直到输入的'n'或'N'退出程序。其代码如下:
#include <iostream>
using namespace std;
void main()
{
int iYear; //定义一个输入的年份变量
char choice; //定义一个是否继续输入的变量
do{
system("cls");
cout << "请输入年份:" << endl;
cin >> iYear;
//判断输入年份是否为闰年
if(iYear%4==0 && iYear%100!=0 || iYear%400==0)
cout << "该年份为闰年" << endl;
else
cout << "该年份不为闰年" << endl;
cout<<"是否继续?Y/N"<<endl;
cin>>choice;
if((choice=='n')||(choice=='N')) //如果输入的'n'或'N'
break;
}while(1);
system("pause");
}
【案例分析】
(1)实例中的几个算术运行符,'“%'”表示取模运算(module),取模运算是取两个整数相除的余数;'“=='”是一个判断等于的关系运算符,用来判断运算符两边的表达式是否相等;'“!='”表示不等于,功能上和判断'“=='”正好相反。
(2)代码中有格式do语句statement while(条件condition)的语句do{…}while(1);。语句中的条件condition如若一直是为真,就一直循环下去。代码中的Break;语句,该语句表示即使在结束条件没有满足的情况下,也可以跳出一个循环,用来结束一个无限循环,或强迫循环在其自然结束之前结束。
提示:数学运算符是编程的基础,要多编程熟练掌握。
案例2-5 打印ASCII码表
【案例描述】
从本实例开始学习控制结构,C++提供一些控制结构语句(control structures)来实现这些执行顺序。本实例通过要求循环打印0到127的ASCII码,效果如图2-5所示。
图2-5 打印ASCII码表
【实现过程】
程序初始化变量并且赋值,然后执行for,输入0到127的值赋给pch字符串,再执行一个for打印pch字符串的每一个ASCII码。代码如下:
#include <iostream>
using namespace std;
void main()
{
char szArr[129] = {'\0'}; //定义一个数组并初始化
char* pch = NULL; //定义一个字符串指针并初始化
int i = 0;
int nArr[10] = {0} ; //定义一个数组并初始化
int* pn = NULL;
//输入0到127的值到pch字符串中
for (i = 0, pch = szArr; pch < szArr + 128; pch++, i++)
{
*pch = i;
// cout << i<<endl;
}
//打印pch字符串中的每一个ASCII码
for (pch = szArr; pch < szArr + 128; pch++)
{
cout << *pch << "\t";
// printf("%s", szArr);
}
cout << endl;
system("pause");
}
【案例分析】
(1)for (i = 0, pch = szArr; pch < szArr + 128; pch++, i++)循环语句中变量i一直累加,字符串指针pch指向内存开始的位置,并赋值'\0',也就是一个字节长度,然后pch指针一直累加往后移动位置赋值'\0',直到127位置结束。
(2)ASCII码使用指定的7位或8位二进制数组合来表示128或256种可能的字符。标准ASCII码也叫基础ASCII码,使用7位二进制数来表示所有的大写和小写字母,数字0到9、标点符号,以及在美式英语中使用的特殊控制字符。上面上述代码中,范围0到127个,为基础ASCII码。
提示:for循环语句也可以用while代替,char* pch为字符串指针,第5章实例会详细描述。
案例2-6 求完数
【案例描述】
本实例演示的也是控制结构,C++提供一些控制结构语句来实现这些执行顺序。本实例输入一个整数求完数,效果如图2-6所示。
【实现过程】
程序初始化变量,然后执行for循环从2到输入要寻找完数m的值,再执行一个 j和i进行取模运算。代码如下:
#include <iostream>
using namespace std;
void main()
{
int k0,k1,k2,k3,k4,k5,k6,k7,k8,k9; //定义整型变量
int m,i,j,n,s; //定义整型变量
cout<<"请输入要寻找完数的范围:";
cin>>m; //取得一个整数
for (j=2;j<=m;j++) //从2到m循环
{
n=0;
s=j;
for (i=1;i<j;i++) //从1到j循环
{
if ((j%i)==0) //j和i进行%运算
{
n++; //同于n=n+1
s=s-i;
switch(n)
{
case 1: k0=i; break;
case 2: k1=i; break;
case 3: k2=i; break;
case 4: k3=i; break;
case 5: k4=i; break;
case 6: k5=i; break;
case 7: k6=i; break;
case 8: k7=i; break;
case 9: k8=i; break;
case 10: k9=i; break;
} } }
if (s==0)
{
cout<<j<<"是一个完数!它的因子是:";
if (n>1) cout<<k0<<" "<<k1<<" ";
if (n>2) cout<<k2<<" "; //如n大于2
if (n>3) cout<<k3<<" ";
if (n>4) cout<<k4<<" ";
if (n>5) cout<<k5<<" ";
if (n>6) cout<<k6<<" ";
if (n>7) cout<<k7<<" ";
if (n>8) cout<<k8<<" ";
if (n>9) cout<<k9<<" ";
cout<<endl;
} } system("pause"); }
【案例分析】
(1)一个数如果恰好等于它的因子(不包含自身的所有因子)之和,这个数就称为“完数”。例如,6的因子为1、2、3,而6=1+2+3,因此6是完数。
(2)取模运算是取两个整数相除的余数,例如,如果写a = 17 % 3;,变量a的值将会为结果2,因为2是17除以3的余数。
案例2-7 密码验证(if)
【案例描述】
编程中时经常要用到if控制结构对变量进行比较。本例介绍的是输入的字符串和密码进行比较,直到输入密码正确或自己退出输入为止。本例效果如图2-7所示。
图2-7 密码验证(if)
【实现过程】
程序定义全局变量mimaStr,这里的密码是固定的,为“123456”。定义一个验证密码的函数YanZheng_mima(),该函数提示输入密码,取得输入的密码,然后,判断如果输入的密码是对的,那么提示成功,按任意键退出,否则提示“验证不成功!按Enter继续验证”,这时按任意键可退出程序。代码如下:
#include <iostream>
#include <conio.h>
#include <string.h>
using namespace std;
char mimaStr[100]="123456"; //全局变量
void YanZheng_mima() //验证密码
{
system("cls");
char ch;
char str[100];
int i=0;
cout<<"请输入你要验证的密码长度大于5,Enter结束: ";
ch=getch();
while (i<100)
{
if (ch=='\r' && i>5)break;
else if(ch=='\r')ch=getch(); //读取一个字符
else
{
cout<<"*";
str[i++]=ch;
ch=getch();
}
}
str[i]=0;
cout<<endl;
if (strcmp(str,mimaStr)==0) //和密码进行比较
{
cout<<"恭喜!验证成功!任意键返回..."<<endl;
ch=getch();
}
else
{
cout<<"验证不成功!按Enter继续验证,任意键返回..."<<endl;
ch=getch();
if (ch=='\r')
YanZheng_mima(); //继续验证密码
}
}
void main()
{
YanZheng_mima();
}
【案例分析】
(1)条件结构用来实现仅在某种条件满足的情况下才执行一条语句或一个语句块。格式是:if (condition) statement;这里的condition是一个用来计算的表达式;。如果表达式值为真,即条件(condition)为true,statement将被执行;否则statement将被忽略(不被执行),程序从整个条件结构之后的下一条语句继续执行。也可以用关键字else来指定当条件不能被满足时需要执行的语句,它需要和if一起使用,格式是:if (condition) statement1 else statement2 ,如代码中的if (strcmp(str,mimaStr)==0){...}else{...}就是这种。
(2)while是一个循环结构,形式是:while ( expression ) statement。当expression的值为真(true)时,重复执行statement。程序中可以输入长度为100内的字符串,当输入的字符串大于5,并按回车键退出输入。while语句中有多个if else的结构被连接起来使用来判断输入字符的值。
提示:在while语句中,当需要执行多条语句时,必须使用花括号{}将它们括起来以组成一个语句块。
案例2-8 图书管理(if else)
【案例描述】
本实例继续讨论if else控制语句的使用。以一个图书管理系统为例,用多个if else控制输入的选择,执行相应的语句或函数。本实例的目标是加深对if else控制语句的认识,以便在以后编程中灵活应用。本例,效果如图2-8所示。
图2-8 图书管理(if else)
【实现过程】
(1)定义4个函数,分别是borrowtoreturn、bookmange、readermange和mainjiemian。readermange()是读者数据维护模块,提示输入选择,取得输入选择,用多个if else 的结构连接起来判断输入数值,进行相应的处理。mainjiemian()显示一个图书管理系统的主界面。代码如下:
#include<iostream>
using namespace std;
void borrowtoreturn(int in)
{
cout<<"借书还书处理完毕:"<<endl;
}
void bookmange()
{
cout<<"图书管理维护完毕:"<<endl;
}
void readermange() //读者维护
{
int in1;
do{
cout<<"1.增加读者 2.删除读者 3.编辑读者4.查找读者5.显示所有的读者 其他.退出:"<<endl;
cin>>in1;
if(in1==1)
cout<<"增加读者:"<<endl;
else if(in1==2)
cout<<"删除读者:"<<endl;
else if(in1==3)
cout<<"编辑读者:"<<endl;
else if(in1==4)
cout<<"查找读者:"<<endl;
else if(in1==5)
cout<<"显示所有的读者:"<<endl;
else
break;
}while(in1!=6);
return;
}
void mainjiemian()
{
cout<<"**************图书管理系统***************"<<endl;
cout<<"**************1.借书*********************"<<endl;
cout<<"**************2.还书*********************"<<endl;
cout<<"**************3.图书管理*****************"<<endl;
cout<<"**************4.用户管理*****************"<<endl;
cout<<"**************5.退出*********************"<<endl;
}
(2)主程序显示一个图书管理系统主界面,然后执行do{…}while 循环,和上面一样用多个if else的结构连接起来判断输入的数字,输入5后退出程序。代码如下:
int main(int argc, char* argv[])
{
int in;
do{
mainjiemian(); //图书管理系统
cin>>in;
if(in==1)
borrowtoreturn(in); //判断是借书,还是还书
else if(in==2)
borrowtoreturn(in);
else if(in==3)
bookmange(); //图书管理
else if(in==4)
readermange(); //读者维护
else if(in==5)
break;
else
cout<<"输入错误,请重新输入:"<<endl;
}while(in!=5);
return 0;
}
【案例分析】
(1)多个if else的结构连接起来用于判断数值的范围,如函数readermange()和主函数中都利用这个结构。
(2)程序中用到do{…}while循环结构,格式如下:
do statement while( expression );
在do-while循环中是先执行statement,然后才检查条件expression,不满足条件则退出循环。
提示:对于多个if else的结构的代码,实际上可以用选择结构switch语句,这样更简洁。
2.3 循环语句
案例2-9 输入符合条件整数(跳出循环)
【案例描述】
算法中通常是符合条件要则循环计算,当条件不满足时候就跳出循环。,如进行递归就是这样的,条件不满足时就会一直计算下去。下面举一个跳出循环的实例,效果如图2-9所示。
图2-9 输入符合条件整数(跳出循环)
【实现过程】
有一个恒为true的while结构,不断提示用户输入一个整数,当输入的整数能被5整除的时候,执行break语言语句跳出循环;,否则,循环将一直进行下去。其代码如下:
#include <iostream>
using namespace std;
int main()
{
using namespace std;
int number;
while (true) //这里是死循环,一直执行下去
{
cout<<"输入一个被5整除的整数:"<<endl;
cin>>number; //取得一个输入整数
if (number % 5==0) //如number可被5整除
{
cout<<"输入一个整数能被5整除";
break; //break用于跳出while循环结构
}
// return 0;
}
}
【案例分析】
(1)上面的代码while (true)是死循环,一直执行下去,所以循环中有一个判断条件跳出循环,break为跳出循环语句。
(2)代码if(number % 5==0),使用了break语句,用于跳出while循环结构。
提示:在以后实例提到的递归算法中,需要跳出循环的判断。
案例2-10 买水果小游戏(开关结构综合)
【案例描述】
实例013演示了一个买水果的例子,用于理解判断语言语句的应用。例子中应用了switch语句,供选择输入,本实例在此基础上作了修改了下,加入do{…}while语句,实现测试心算能力的功能。本例效果如图2-10所示。
图2-10 买水果小游戏(开关结构综合)
【实现过程】
提示输入水果重量,然后取得重量值,输入水果品种编号,取得品种编号对应的价格,计算应付的钱,提示输入心算应付价钱,输入误差在1元内应付的价钱,程序提示输入正确。代码如下:
#include <iostream>
#include <iostream.h>
#include <math.h>
int main()
{
int type,sum=0,guess_price;
double sale,weigt=0,price;
std::cout << "输入水果重量:" << std::endl;
std::cin >>weigt;
std::cout << "0.西瓜1.80 1.木瓜1.70 2.哈密瓜2.60 3.山竹1.60" << std::endl;
std::cout << "输入水果品种编号:" << std::endl;
std::cin >>type;
switch (type) //输出数字
{
case 0: //西瓜
std::cout << "输入水果品种---西瓜,每公斤1.80" << std::endl;
price=1.80;
break;
case 1:
std::cout << "输入水果品种---木瓜,每公斤1.70" << std::endl;
price=1.70;
break;
case 2:
std::cout << "输入水果品种---哈密瓜,每公斤2.60" << std::endl;
price=2.60;
break;
case 3:
std::cout << "输入水果品种---山竹,每公斤1.60" << std::endl;
price=1.60;
break;
daulft:
break;
}
if (weigt<=0)
sale=0.00;
else
sale=weigt*price; //计算应付价钱
// std::cout <<sale;
do
{
std::cout << "输入你心算水果应付人民币,准确到元,输入0退出:" << std::endl;
std::cin >>guess_price;
switch (guess_price)
{
case 0: break;
default: {
//允许误差1元
if((guess_price==(int)sale)||(guess_price== (int)sale+1)||(guess_price==(int)sale-1))
std::cout << "恭喜你答对了,你心算能力很强";
break;
}
}
}while(guess_price!=0);
system("pause");
return 0;
}
【案例分析】
(1)switch语句中,每个语句块结尾包含的break语句。因为如果不这样做,程序将不会跳转,例如,在语句块price=1.80;中,结尾没有break,程序执行将不会跳转到switch选择的结尾处(}),而是继续执行下面的语句块,直到第一次遇到break语句或到switch选择结构的结尾。所以在程序中,不需要在每一个case域内加花括号{ }。这个特点同时可以帮助实现对不同的可能值执行相同的语句块。
(2)语句do{ ...} while(guess_price!=0);,是循环结构,先执行{...}中的代码,然后才检查条件(guess_price!=0),条件不满足时也就是这时,输入0结束循环。
提示:上面代码的switch语句中,代码不多很容易用if和else if语句改写。
案例2-11 用循环计算9的9次方(for)
【案例描述】
在编程的时候经常要循环计算实现数学计算的功能。循环中的变量值是有规律的增量或减量。本实例就是用for处理循环计算问题,实现计算9的9次方的功能,效果如图2-11所示。
图2-11 用循环计算9的9次方(for)
【实现过程】
程序的功能很简单,就是计算9的9次方,定义了3个变量并初始化代码为int x=9; double k=1;,然后利用for实现循环计算。其代码如下:
#include<iostream>
#include<math.h>
using namespace std;
int main()
{
int x=9;
double k=1;
int y;
for (y=0;y<9;y++) //从0循环到8
{
k=k*x; //每次循环乘以9
}
cout<<"循环计算出的9的9次方="<<k<<endl;
cout<<"pow(9,9)计算出9的9次方="<<pow(9,9)<<endl;
system("pause");
}
【案例分析】
(1)代码中的for循环,格式:为
for( for-init-statement; expression1; expression2 ){ statements}。
主要功能是当条件expression1为真(true)时,重复执行语句statement,与类似while循环类似。但除此之外,for还提供了初始化语句for-init-statement和增值语句expression2。因此,这种循环结构是特别为执行由计数器控制的循环而设计的。
(2)用for循环计算9的9次方,实际上可以用数学函数pow代替,结果是一样的。Pow的头文件是math.h。
提示:for循环的功能和while功能很类似,一般通常可以相互替换。
案例2-12 寻找出口小游戏(do while)
【案例描述】
本实例为综合例子,多处用到循环语句do{…}while和for循环语言语句,目的是加深读者对循环语句的认识。程序随机产生一个数,规定5次以内猜猜该数的最大素数,效果如图2-12所示。
图2-12 寻找出口小游戏(do while)
【实现过程】
(1)用初等数学的方法判断素数函数Fun();判断最大素数函数Fun1(int n,int inputdig);代码中的n为随机产生的一个数,inputdig为输入的最大素数。其代码如下:
# include <iostream.h>
# include <iostream>
# include <math.h>
# include <time.h>
//根据初等数学知识,一个整数若不能被2到它其平方根之内(N+1)的数整除,就是素数
bool Fun(int N)
{
bool return_flag = true;
for (int i = 2; i <= sqrt(N +1); i++)
{
if (N % i == 0)
{
return_flag = false;
break;
}
return_flag = true;
}
return return_flag;
}
bool Fun1(int n,int inputdig)
{
if(!Fun(inputdig)) //不是素数
{
return false;
}
int sta=n;
while (sta>1) //直到sta大于输入的数
{
if(Fun(sta)) //是素数
{
// cout<<"sta="<<sta;
if(sta==inputdig) //最大的素数
return true;
else return false;
}
sta--;
}
return false;
}
(2)主函数产生一个随机数,提示出口密码为小于该数最大的素数,循环语句do{…}while有5次机会,调用Fun1()判断是否为最大的素数,如猜对了,提示密码正确,若超过5次机会没有猜对,就退出程序提示输入密码失败。代码如下:
void main()
{
int inputdig;
int inputdig_time=0;
int num;
time_t timenow;
do
{
srand((unsigned)time(&timenow));
num=rand(); //产生一个随机数
if (num>100) break;
}while(1);
cout<<"出口密码为小于"<<num<<"最大的素数"<<endl;
cout<<"请你猜猜看,输入0结束"<<endl;
do
{
cin>>inputdig;
if(inputdig==0)
break;
if(Fun1(num, inputdig))
{
cout<<endl<<"恭喜你!寻找出口密码输入正确!"<<endl;
break;
}
inputdig_time++;
if(inputdig_time<5)
cout<<"还有"<<5-inputdig_time<<"机会"<<"再猜猜看,输入0结束"<<endl;
}while(inputdig_time<5);
if(inputdig_time==5)
cout<<endl<<"很遗憾!!,寻找出口密码没有猜到。"<<endl;
system("pause");
}
【案例分析】
(1)程序中有3处用到了循环语句do{…}while,一处用到了循环语句for。
(2)代码中N % i为%取模运算,!Fun(inputdig)为Fun(inputdig)返回值取反,运算符(!)等同于boolea运算NOT(取非),只有一个操作数,写在其右边。运算符唯一的作用就是取该操作数的反面值。
提示:for循环语言语句和循环语句do{…}while循环语句在实际编程中经常用到,读者应细心观察使用细节。
案例2-13 剪刀石头布
【案例描述】
本实例演示的是一个简单的剪刀石头布游戏,程序执行后,随意输入玩家甲和玩家乙所出的招数,由电脑判判断谁是赢家。效果如图2-13所示。
图2-13 剪刀石头布
【实现过程】
程序代码很少,while循环提示再玩一次,程序读取甲的出拳和读取乙的出拳,然后用if语句判断是那方胜。代码如下:
#include<iostream> //剪刀石头布
using namespace std;
int main()
{
char one ,other,ans='y';
while(ans=='Y'||ans=='y')
{
cout<<"请玩家甲分别在R(表示石头)、S(表示剪刀)、P(表示布)各选一个:";
cin>>one; //读取甲的出拳
cout<<"请玩家乙分别在R(表示石头)、S(表示剪刀)、P(表示布)各选一个:";
cin>>other; //读取乙的出拳
if(one=='R'||one=='r') //甲的出拳石头
{
if(other=='R'||other=='r')cout<<"平局\n";
else if(other=='S'||other=='s')cout<<"玩家甲\n";
else cout<<"玩家乙\n";
}
if(one=='S'||one=='s') //甲的出拳剪刀
{
if(other=='R'||other=='r')cout<<"玩家乙\n";
else if(other=='S'||other=='s')cout<<"平局\n";
else cout<<"玩家甲\n";
}
if(one=='P'||one=='p') //甲的出拳布
{
if(other=='R'||other=='r')cout<<"玩家甲\n";
else if(other=='S'||other=='s')cout<<"玩家乙\n";
else cout<<"平局\n";
}
cout<<"您还想再玩一次吗?(Y表示是,N表示否):";
cin>>ans;
}
return 0;
}
【案例分析】
“石头、剪子、布”通常是用手来玩。握紧的拳头代表“石头”,食指和中指伸出代表“剪子”,五指伸开代表“布”。游戏规则是出拳之前双方齐喊口令“石头、剪刀、布”,然后同时出拳。 “石头”胜“剪子”,“剪子”胜“布”,而“布”又胜过“石头”。
提示:上面代码if语句,也可以用switch来代替。
案例2-14 编写一个屏幕小时钟程序
【案例描述】
软件开发中经常用到绘图功能,如开发股票软件,需要用不同的颜色和曲线显示股票价格和走势,本实例用第三方提供的绘图软件库,实现一个简单的钟表模拟程序,使用了for和while循环语言。本例效果如图2-14所示。
图2-14 编写一个屏幕小时钟程序
【实现过程】
定义2个函数DrawHand()和DrawDial(),分别为画表针和绘制表盘;主函数为初始化绘图窗口,绘制表盘、获取当前时间、画表针、擦表针。代码如下:
#include <graphics.h>
#include <conio.h>
#include <math.h>
#define PI 3.1415926536
void DrawHand(int hour, int minute, int second) //画表针 { //代码略 }
void DrawDial() //绘制表盘
{
//绘制一个简单的表盘
circle(320, 240, 2);
circle(320, 240, 60);
circle(320, 240, 160);
outtextxy(296, 310, "BestAns");
//绘制刻度
int x, y;
for (int i=0; i<60; i++)
{
x = 320 + int(145 * sin(PI * 2 * i / 60));
y = 240 + int(145 * cos(PI * 2 * i / 60));
if (i % 15 == 0)
bar(x - 5, y - 5, x + 5, y + 5);
else if (i % 5 == 0)
circle(x, y, 3);
else
putpixel(x, y, WHITE); //在指定位置画一像素
}
}
void main()
{
initgraph(640, 480); //初始化 640 x 480 的绘图窗口
DrawDial(); //绘制表盘
setwritemode(R2_XORPEN); //设置 XOR 绘图模式
//绘制表针
SYSTEMTIME ti; //定义变量保存当前时间
while(!kbhit()) //按任意键退出钟表程序
{
GetLocalTime(&ti); //获取当前时间
DrawHand(ti.wHour, ti.wMinute, ti.wSecond); //画表针
Sleep(1000); //延时 1 秒
DrawHand(ti.wHour, ti.wMinute, ti.wSecond); //擦表针(擦表针和画表针的过程是一样的)
}
closegraph(); //关闭绘图窗口
}
【案例分析】
(1)graphics.h是TC(Turbo C)下的绘图的库,VC++下不能用。如果想在VC++下用,也是有办法的。在官网http://www.easyx.cn/,下载提供的EasyX库。在使用上,基本和TC里面的graphics.h没太大区别。
(2)initgraph()初始化绘图窗口,circle()画圆,line()画线,setcolor()设置颜色。
提示:VC++是通过创建GDI对象实现绘图功能。
案例2-15 屏幕变色效果——使用system()函数改变屏幕颜色
【案例描述】
在DOS命令行窗口中,执行一条命令system(),也就是调用DOS命令,使用system()函数改变屏幕颜色。下面就是一个改变屏幕和字体颜色实例,效果如图2-15所示。
图2-15 屏幕变色效果——使用system()函数改变屏幕颜色
【实现过程】
程序switch语句选择不同的背景色和文字色,然后暂停,最后屏幕恢复亮白色背景、黑色字。其代码如下:
#include <iostream>
#include <windows.h>
using namespace std;
void main(void )
{
int i=10;
switch(i)
{ case 9: system("color 49"); //红色背景淡蓝色字
case 10: system("color 12" ); //蓝色背景绿色字
case 11: system("color 56" ); //紫色背景淡紫色字
default: system("color 34" ); //湖蓝色背景红色字
}
cout<<"system(color )="<<i<<endl;
system("pause");
system("color F0"); //恢复亮白色背景黑色字
system("pause");
}
【案例分析】
(1)代码中调用windows.h中的一个函数system(color a),其中a代表颜色属性,如system(color 08),表示“黑色背景灰色字”颜色属性。颜色属性由两个十六进制数字指定,第一个为背景,第二个则为前景。每个数字可以是表11-1中的值之一。
表11-1 颜色表
0 |
黑色 |
1 |
蓝色 |
2 |
绿色 |
3 |
湖蓝色 |
4 |
红色 |
5 |
紫色 |
6 |
黄色 |
7 |
白色 |
8 |
灰色 |
9 |
淡蓝色 |
A |
淡绿色 |
B |
淡浅绿色 |
C |
淡红色 |
D |
淡紫色 |
E |
淡黄色 |
F |
亮白色 |
|
|
|
|
(2)Windows下API函数COLORREF SetBkColor( HDC hdc, COLORREF crColor ),该函数用指定的颜色值来设置当前的背景色。
案例2-16 屏幕背景闪动效果的实现
【案例描述】
继续上面203实例演示,利用for循环和改变屏幕颜色功能函数system(color a),实现屏幕背景闪动效果。本例效果如图2-16所示。
图2-16 屏幕背景闪动效果的实现
【实现过程】
程序switch语句选择不同的背景色和文字色,然后暂停,最后屏幕恢复亮白色背景、黑色字。代码实现如下:
#include <iostream>
#include <windows.h>
using namespace std;
void main(void )
{
int i;
for(i=0;i<20;i++)
{
switch(i)
{ case 9: system("color 49"); //红色背景、淡蓝色字
case 10: system("color 12" ); //蓝色背景、绿色字
case 11: system("color 56" ); //紫色背景、淡紫色字
default: system("color 34" ); //湖蓝色背景、红色字
}
}
cout<<"system(color )="<<i<<endl;
system("pause");
system("color F0"); //恢复亮白色背景、黑色字
system("pause");
}
【案例分析】
上面代码for循环从0到19,switch选择不同的值,system(color a),变换不同的屏幕颜色值。
案例2-17 终极密码
【案例描述】
紧接上面实例262的话题,还是产生随机数。如互联网上经常要随机产生要验证的图片,图片的内容是随机出现的数字或字母,这些实际上都是随机数的问题。本例实现简单猜密码功能,效果如图2-17所示。
图2-17 终极密码
【实现过程】
while循环提示输入密码,scanf()取得输入的密码,如密码正确的提示,错误则提示还能重输的次数。其代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main()
{
int a, b, ans, user, life, win;
srand(time(NULL)); //随机数发生器的初始化函数
while(1){
a=1;
b=100;
ans=(rand()%98)+2; //产生1~100的数
life=7; //最多能猜7次
win=0;
printf("[终极密码]\n范围:1~100 最多尝试次数: 7次\n如未在7次内猜到正确答案就算是输了游戏!\nGood Luck!");
while(1){
printf("\n\n[已尝试: %d 剩余数: %d]\n", (7-life), life);
printf("请输入一个介于%d到%d之间的数字:", a, b);
scanf("%d", &user); //读取输入的答案
if((user > a) && (user < b)){ //答案范围
if(user == ans){ //猜对了
win = 1;
break;
}
else{
life--; //允许的次数减去1
if (user > ans) b=user;
else a=user;
}
}
else { //超出答案范围
printf("你输入数字不符合规定,请重新输入…\n\n");
}
if((life == 0) || (win == 1)) break; //允许的次数超过或猜对了
}
if (win == 1){ //猜对了
printf("\nBingo!\a\a\n\n");
printf("恭喜, 你贏了!\n\n");
system("pause");
printf("\n\n\n下一位…\n");
printf("——————————————————–\n\n");
}
else{ //在允许的范围未猜对
printf("\n抱歉, 您输了这次游戏, 请再试一次.\a\n");
printf("正确答案是: %d\n" ,ans);
system("pause");
printf("\n重新开始…\n\n");
}
}
}
【案例分析】
(1)终极密码每个队伍有七次机会供猜中正确答案,猜中了正确答案就算过关,否则就要重新开始。一个人当裁判,由裁判出1到100之间任意一个数字,然后大家轮流说一个数字,由裁判给出范围,直到说到裁判出的那个数字的人中,中的人当裁判。例子:密码是27然后挨个说出数字,有人说68,裁判就要说1到68之间.接下来就要说1到68之间的数字,可以任意喊。
(2)srand()函数是随机数发生器的初始化函数。原型:void srand(unsigned seed),通过srand(time(NULL))使得随机数种子随时间的变化而变化。time()函数获取当前的系统时间,返回的结果是一个time_t类型。
提示:time_t其实就是一个大整数,其值表示从CUT(Coordinated Universal Time)时间1970年1月1日00:00:00(称为UNIX系统的Epoch时间)到当前时刻的秒数。
案例2-18 彩票游戏
【案例描述】
紧接上面实例263的演示,还是产生随机数的问题。如彩票每期都是随机摇号码,可以编写一个程序模拟摇奖,然后看是否中奖也就是有没有猜对号码,实际上都是随机数的问题。本实例随机产生号码和用户选号,来模拟彩票中自选号码功能,效果如图2-18所示。
图2-18 彩票游戏
【实现过程】
(1)这是25选3函数,for循环产生3组随机数。其代码如下:
void choice_25() //25选3
{
int Num[3];
int SysNum[3];
srand((int)time(0));
for(int j=0;j<3;j++) //for循环
{
SysNum[j]=1+rand()%25; //产生3组随机数
}
cout<<"您好,您选择的是25选3的彩票!";
cout<<"请输入您理想的3个号码...祝您中奖!\n";
for(int i=0;i<3;i++) //取得输入3组号码
{
cout<<"第"<<i+1<<"个号码:";
while(!(cin>>Num[i])||Num[i]>25) //直到输入整数并且不大于25
{
cin.clear();
while(cin.get()!='\n') //直到输入回车
continue;
cout<<"输入不正确,请重新输入第"<<i+1<<"个号码:";
}
}
for(int m=0;m<5;m++)
cout<<"\a"; //中奖号码开出前,鸣笛10下
compare(Num,SysNum,3);
}
(2)这是判断是否中奖函数,输入自选号码和随机开出号码,for循环中了几组,如果全部组中了,提示中奖。其代码如下:
void compare(int a[],int b[],int count) //看是否中奖
{
int *YourNum=a; //选号码
int *LotteryNum=b; //开奖号码
int Lucky;
for(int x=0;x<count;x++) //count组数
{
if(YourNum[x]==LotteryNum[x])
Lucky++;
}
if(Lucky==count) //每组都中
{
cout<<"这也能中,你太牛比了吧,赶紧买彩票去!";
}
else
cout<<"对不起,你没能中奖!\n";
cout<<"本期Lottery号码是...\n";
for(int y=0;y<count;y++) //打印开奖号码
{
cout<<"Lottery["<<y<<"]:"<<LotteryNum[y]<<endl;
}
}
【案例分析】
(1)choice_25()、choice_35()、choice_47()实现原理基本上时一样的,都是产生随机数,输入自选号码调用compare()是否中奖。
(2)产生随机数srand()函数是随机数发生器的初始化函数。
案例2-19 随机数是否随机
【案例描述】
在摇号、彩票等活动中,每次产生的数字是不同的。怎样用C++语言产生不同的数字,本实例通过srand()随机函数产生每次不同的数字。效果如图2-19所示。
图2-19 随机数是否随机
【实现过程】
srand()产生随机种子,定义10个双精型变量并初始化;for循环里面rand()产生不同的随机数,根据这个随机数的值,和之中的随机数累加变化值,最后得出不同的随机数。其头文件代码如下:
#include <iostream>
#include <ctime>
using namespace std;
int main()
{
srand((unsigned)time(0)); //随机种子
double x;
double y1,y2,y3,y4,y5,y6,y7,y8,y9,y10; //定义双精型
y1=y2=y3=y4=y5=y6=y7=y8=y9=y10=0; //初始化
for(double i=1;i<=1000000;i++)
{
x=rand()%10+1; //产生10内随机数
if(x==1) y1++;
else if(x==2) y2++; //产生的随机数
else if(x==3) y3++;
else if(x==4) y4++;
else if(x==5) y5++;
else if(x==6) y6++;
else if(x==7) y7++;
else if(x==8) y8++;
else if(x==9) y9++;
else y10++;
}
cout<<"输出10个随机为:"<<endl;
cout<<y1/1000000<<endl; //输出数据数
cout<<y2/1000000<<endl;
cout<<y3/1000000<<endl;
cout<<y4/1000000<<endl;
cout<<y5/1000000<<endl;
cout<<y6/1000000<<endl;
cout<<y7/1000000<<endl;
cout<<y8/1000000<<endl;
cout<<y9/1000000<<endl;
cout<<y10/1000000<<endl;
system("pause");
}
【案例分析】
(1)代码srand((unsigned)time(0));,用0调用时间函数time(),将其返回值强制转换为unsigned型,作为参数来调用srand()函数。srand()是为rand()函数初始化随机发生器的启动状态,以产生伪随机数,所以常把srand()称为种子函数。用time()返回的时间值做种子的原因是time()返回的是实时时间值,每时毎刻都在变化,这样产生的伪随机数就有以假乱真的效果。
(2)代码中for循环,运用rand()多次产生不同的随时数。
案例2-20 抢答数学题
【案例描述】
计算机随机出题选手抢答,要求进入每种题型比赛时,计算机均有提示,每队的记分窗口随得分情况而更新。要实现这些功能就涉及到随机数、程序输入和输出,本例效果如图2-20所示。
图2-20 抢答数学题
【实现过程】
定义四个函数,分别是加、减、乘、除,srand()和rand()随机产生两个计算的数,显示计算表达式,取得输入的值,判断结果是否正确。加法运行代码实现如下:
void jiafys()
{
int a,b,c,sum=0;
cout<<"=====加法运算====="<<endl;
for(int i=0;i<5;i++)
{
srand((unsigned)time(NULL)); //随机数发生器的初始化函数
a=rand()%10+1; //产生随机数1到10
srand((unsigned)time(NULL)); //随机数发生器的初始化函数
b=rand()%100+1; //产生随机数1到100
cout<<b<<'+'<<a<<"=";
cin>>c; //读取输入的数
if(b+a==c) //答案是对的
{
sum++;
cout<<"真棒!"<<endl;
}
else //答案是错的
cout<<"继续努力!"<<endl;
}
switch(sum)
{
case 1: cout<<"你的成绩为:E 等"<<endl;break;
case 2: cout<<"你的成绩为:D 等"<<endl;break;
case 3: cout<<"你的成绩为:C 等"<<endl;break;
case 4: cout<<"你的成绩为:B 等"<<endl;break;
case 5: cout<<"你的成绩为:A 等"<<endl;
}
getchar(); //按任意键
}
【案例分析】
(1)本实例主要是利用随机函数random()、randomsize()来实现游戏功能。游戏均为二位数以内的四则运算。程序中乘法的乘数为个位数,除法的除数为个位数并不能为零,商必须是整数;每种运算运行五次,成绩分别用A、B、C、D和E五档标识。
(2)main()模块功能:定义数据,菜单设计,调用相关子模块;menu()模块功能:实现流程图的过程;jiafys()、jianf()、cfys()、chufys()模块功能:定义数据,编写for循环语句,编写加法、减法、乘法、除法数学运算,条件if else语句和开关语句switch语句。
提示:实际上编写加法运算jiafys()这个函数,其他四则运算函数都是类似的。
2.4 本章练习