这部分内容可以放在考试后再安排,但上机报告一定要看到。
除了基本的数据类型,C++还定义了一个内容丰富的抽象数据类型标准库。通过使用标准库中的组件,通常可以避免从头到尾来设计自己的IO流,string,容器,国际化,数值数据结构以及诊断等机制。程序员可以方便地调用标准库,以便有更多的时间和精力去关注软件开发中真正重要的部分——实现软件的其他功能。这也是提高软件质量的的一个有利条件。
C++标准库非常大,在C++标准中,关于标准库的规格说明占了密密麻麻300多页。标准库中的功能越多,开发自己的应用程序时能借助的功能就越多。所以,学习C++过程中,如果能够多了解一些标准库,无疑对高效率开发是有帮助的。C++是面向对象的语言,对标准库的完整介绍自找有关材料,这部分拓展针对读者仅有函数调用的知识背景,仅介绍系统函数的使用方法。系统函数是标准库中提供的可以完成特定功能的函数。
调用系统函数时,都需要用#include<...>指定需要的头文件。例如,调用有关的数学函数时,需要在程序开始处用#include<Cmath>。调用的函数需要用哪个头文件,需要学习者知道。
1、常用系统函数:数学、随机数、时间、系统
(1) 数学函数
C++的标准数学函数需要用#include<Cmath>指定包含的头文件。下面是常用的数学函数,<Cmath>的内容与C语言的<math.h>中的内容相同,也可以写作
#include<math.h>。 double log(double x) 返回logex的值 double log10(double x) 返回log10x的值 double pow(double x,double y) 返回xy的值 double pow10(int p) 返回10p的值 double sqrt(double x) 返回x的正平方根值 double acos(double x) 返回x的反余弦cos-1(x)值,x为弧度 double asin(double x) 返回x的反正弦sin-1(x)值,x为弧度 double atan(double x) 返回x的反正切tan-1(x)值,x为弧度 double atan2(double y,double x) 返回y/x的反正切tan-1(x)值,y的x为弧度 double cos(double x) 返回x的余弦cos(x)值,x为弧度 double sin(double x) 返回x的正弦sin(x)值,x为弧度 double tan(double x) 返回x的正切tan(x)值,x为弧度 double cosh(double x) 返回x的双曲余弦cosh(x)值,x为弧度 double sinh(double x) 返回x的双曲正弦sinh(x)值,x为弧度 double tanh(double x) 返回x的双曲正切tanh(x)值,x为弧度 double hypot(double x,double y) 返回直角三角形斜边的长度(z),x和y为直角边的长度,z2=x2+y2 double ceil(double x) 返回不小于x的最小整数 double floor(double x) 返回不大于x的最大整数
(2)随机数函数
在很多场合,如游戏、计算机仿真等,需要程序产生随机数,以生成或模拟随机性的事件,这时就需要随机数函数了。
C++中的标准库<cstdlib>提供了两个生成伪随机数的函数,<cstdlib>中的内容与C语言中的<stdlib.h>中的内容相同。
这两个生成伪随机数的函数是:
void srand(unsigned seed) 初始化随机数发生器 int rand() 产生一个随机数并返回这个数
函数一:int rand()
功能:从srand()中指定seed开始,返回一个范围介于0到RAND_MAX之间的一个随机整数。RAND_MAX是stdlib.h中定义的一个很大的常量
函数二:void srand(unsigned seed);
参数seed是rand()的随机种子,即用来初始化rand()的起始值。
系统在调用rand()之前都会自动调用srand(),如果用户在rand()之前曾调用过srand()给参数seed指定了一个值,那么 rand()就会将seed的值作为产生伪随机数的初始值;而如果用户在rand()前没有调用过srand(),那么rand()就会自动调用 srand(1),即系统默认将1作为伪随机数的初始值。
由上述可得知,如果希望rand()在每次程序运行时产生的值都不一样,必须给srand(seed)中的参数seed指定一个变值,这个变值必须在每次程序运行时都不一样(比如到目前为止流逝的时间);如果我们给seed指定的是一个定值,那么每次程序运行的时候,rand()产生的随机数序列都会一样,。
常用下面形式的程序,使程序每次执行产生的随机数列不同,其中指定seed的值为当前系统流逝了的时间,单位为秒(time_t time(0)):
【例】产生10个0~5的随机数
#include <iostream> #include<ctime> using namespace std; int main(void) { int i,ran_num; srand(time(0)); //time(0)返回自格林威治时间1970年1月1日凌晨至现在所经过的秒数用种子 for(i=0;i<10;i++) { ran_num=rand()%6; //rand()返回0到RAND_MAX的整型,对6取余保证了随机数为0~5。 cout<<ran_num<<" "; } return 0; }
要想取得[a,b)之间的随机整数,一个通用的公式是:使用(rand()%(b-a))+ a,结果包含 a 而不含 b。
(3)时间日期函数
时间日期函数的函数库为time.h、dos.h。
在时间日期函数里,主要用到的结构有以下几个(关于结构体见第7章,在此处知道简单的时间日期函数的调用形式即可,更深入的理解和应用可以在学习了第7章再“回炉”):
总时间日期贮存结构tm:
struct tm { int tm_sec; /*秒,0-59*/ int tm_min; /*分,0-59*/ int tm_hour; /*时,0-23*/ int tm_mday; /*天数,1-31*/ int tm_mon; /*月数,0-11*/ int tm_year; /*自1900的年数*/ int tm_wday; /*自星期日的天数0-6*/ int tm_yday; /*自1月1日起的天数,0-365*/ int tm_isdst; /*是否采用夏时制,采用为正数*/ }
日期贮存结构date
struct date { int da_year; /*自1900的年数*/ char da_day; /*天数*/ char da_mon; /*月数 1=Jan*/ }
时间贮存结构time
struct time { unsigned char ti_min; /*分钟*/ unsigned char ti_hour; /*小时*/ unsigned char ti_hund; unsigned char ti_sec; /*秒*/ }
在这些结构体支持下,常用的时间日期函数有:
char *ctime(long *clock) 把clock所指的时间(如由函数time返回的时间)转换成形如“Mon Nov 21 11:31:54 1983\n\0”的字符串: double difftime(time_t time2,time_t time1) 计算结构time2和time1之间的时间差距(以秒为单位) struct tm *gmtime(long *clock) 把clock所指的时间(如由函数time返回的时间)转换成格林威治时间,并以tm结构形式返回 struct tm *localtime(long *clock) 把clock所指的时间(如函数time返回的时间)转换成当地标准时间,并以tm结构形式返回 void gettime(struct time *timep) 将计算机内的时间写入结构timep中,以供用户使用 void settime(struct time *timep)本函数将计算机内的时间改为由结构timep所指的时间 long time(long *tloc) 给出自格林威治时间1970年1月1日凌晨至现在所经过的秒数,并将该值存于tloc所指的单元中.
在讲随机数函数的例子中,用srand(time(0))设置种子,其中time(0)返回自格林威治时间1970年1月1日凌晨至现在所经过的秒数,这样取种子可以保证每次的随机数列有所不同。
【例】程序执行需要多长时间?
计算机算法理论中有专门的方法分析算法的时间复杂性和究竟复杂性。在现实中,也经常在某一种环境中测试算法实际执行需要的时间,以比较算法的优劣或运行环境的效率。用下面的一段代码可以输出某段程序执行耗费的时间(秒),可以作为参考。
#include <iostream> #include<ctime> using namespace std; int main(void) { int i,ran_num=0; double t1,t2; t1=time(0); //将要测试的代码放在这里,因为计数单位为秒,简单的代码输出都为0秒。 t2=time(0); cout<<"运行耗时"<<t2-t1<<"秒!"<<endl; return 0; }
(4)关于系统控制的函数
讲exit和system两个函数,它们全都在<stdlib.h>中(在VC++6.0中可以不写入#include)。
这两个函数的原型为:
void exit( int exit_code );
功能:终止程序的执行。参数exit_code 传递给返回值,通常零值表示正常结束,非零值表示应错误返回。
int system( const char *command );
功能:函数返回给定的命令字符串command进行系统调用。如果命令执行正确通常返回零值。如果command 为 NULL, system()将尝试是否有可用的命令解释器。如果有返回非零值,否则返回零值。
命令字符串command是可以调用一些DOS命令,比如:
system("cls"); //清屏,等于在DOS上使用cls命令
下面列出可能在编win32控制台应用程序时可能用到的简单命令。更多命令,以及使用这些命令的格式,可以上网查询:
CLS 清除屏幕。 DATE 显示或设置日期。 PAUSE 暂停批文件的处理并显示消息。 TIME 显示或设置系统时间。 VER 显示 Windows 版本。
2、 方法指导:获得系统函数信息
在C++程序设计中,随着学习的深入,需要知道哪些功能是标准库里已经提供的。在做用户界面、网络通信、科学计算、游戏开发等领域的工作时,还要引入其他的程序库。可以通过手册等资料提前了解在某些库中提供了哪些常量、数据类型以及函数的定义,并且了解在相关函数的说明。
一种方法是利用IDE中提供的帮助功能:
(1)在VC++6.0中选择你需要提供帮助的关键词,或者需要帮助的代码行,击键盘的功能键“F1”,就会出现帮助窗口,一般情况下,其中的内容就是你要的信息,如果你选择的是标准库函数,会出函数的接口说明,有些还会提供使用范例。
(2)选择“帮助”菜单,启动帮助窗口,然后在其中通过搜索、索引等功能找到需要的信息,如图1展示了在帮助窗口中,按time索引找到的信息。
图1 在帮助窗口按time索引查找信息
另外一种方法是在输入程序过程中获得函数的原型,在屏幕提示的参数个数、类型的引导下,正确地输入函数的调用。方法是:在输入完函数名及左括号后,如图2,在“编辑”菜单中,选择“参数信息”,然后在程序编辑区,可以看到图3所示的提示。如果函数在定义中是被重载过的,会列出重载函数的多个提示,由编程人员选择到底用哪一个。
图2 在输入完函数名sqrt及左括号后,在“编辑”菜单中,选择“参数信息”
需要提示的是,如图2的菜单上所示,“参数信息”功能对应的快捷键是“Ctrl+Shift+Space”,在编程中,通过实践记住快捷键将有助于提高工作效率。在这个菜单中列出成员、类型信息、完成字词,以及“高级”的下一层菜单中的选项,都是一些非常实用的功能,可以“试玩”一下,逐渐习惯用好这些功能。
图3 在程序编辑区看到了“参数信息”
最后,还可以找到Cmath、math.h等文件,直接打开查看头文件的定义,感兴趣的同学可以自行探索体验。看头文件的意义同阅读源代码一样,也是一位编程初学者需要经历的学习阶段。
更多信息,可以在线查询“MSDN-微软技术资源库(中文)”,链接是:http://msdn.microsoft.com/zh-cn/library/。
3、上机项目
下学期初要看到上机报告。
【项目1-猜数字游戏】
随机产生一个1000内的数字,要求用户猜测这个整数。输入一个猜测想的整数,判断是否与产生的随机数相等,由屏幕显示判断结果。如果猜得不对,给出“大了”或“小了”的提示,直到猜出这个数为止。(可以再加一个要求,猜中后输出猜了几次。)
【项目2-辅助学习软件开发】
(1)针对小学生学数学,例如对一年级,由计算机自动出一道10以内加减法题目(运算量和运算符都由程序自动产生随机数),小学生输入答案后,提示“做对了”或“还需要努力”(是否“嘀”地响一声刺激一下不努力的学生,由你定,注意不要把孩子吓出毛病来)。;
(2)连续出N个10以内的加减法题目,用户回答后,输出得分;
(3)小明上二年级了,要学1000以内的加减乘除……
(4)想想能让计算机出任意四则运算的数学题,如何设计?
(5)记得我们的电子词典吗?现在做一个辅助记单词的程序。让计算机自动选择出若干(如10个)单词,提示中文,让用户输入英文,提示“对了”或“错了(可以输不对不出下一个)”,或者不提示,10个全答完后给得分,甚至提示用户答题结果和答案的对照表。
【项目3-抽签】
贺老师教3班和4班两个班的C++程序设计课,3班同学的学号为1~28,4班同学的学号为29-56,现在每个班要抽签确定3名同学去参加学校组织的水平测试,请编程完成这个“抽签”的工作。