《C语言程序设计》案例讲义 - 完整版

更新时间:2024-04-24 16:20:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

C语言程序设计 模块一 认识C语言

能力标准:

1. 了解C语言的作用; 2. 熟悉C程序结构;

3. 掌握TC集成调试环境的使用。 知识点:

1. C语言是人和计算机交流的一种工具;

2. C语言程序的执行过程。

1.C语言的发展

计算机语言是计算机和人交流的工具,必须遵守一定的规则,具有一定的书写格式。C语言就是一种计算机语言,诞生于1972年,是由美国电话电报公司(AT&T)贝尔实验室的Dennis.M.Ritchie设计。C语言诞生至今已30多年,其发展经历了ALGOL(1960年)—CPL(1963年)—B(1970年)—C(1972年)的演变过程。

2.人机交流

人和计算机交流可以采用对话形式的一问一答方式,也可采用任务方式,即把需要交流的内容集中在一起,一次性完成。前者的专业述语叫解释方式,后者叫编译方式。用C语言进行人和计算机交流采用的是编译方式。具体过程如下:

? 编程 首先人将和计算机交流的内容按要求,用C语言写成任务,如要计算机计算5!,则需要写出以下任务:

#include

main() {

float m,k,j; k=5; m=1;

for(j=1;j<=k;j++) m=m*j;

printf(“%f !=%f\\n”,k,m); }

上述用C语言表示的任务,称为程序。所谓程序指由一系指令组成,完成某个具体功能的指令集合。

? 编译 计算机本身是一堆零件,它只知道高低电平,对应到二进制就是“0”和“1”这两个符号,当然它是不认识我们用上述符号写成的程序,因此我们需要将上述程序进行转换,转换成由“0”和“1”的组合来表示的二进制程序,也就是机器语言程序。我们把这样的转换称之为编译。

? 连接 为了方便程序的编写,专业人员已经将许多常用的功能写成了固定的程序,并已进行编译,我们在编写实际应用程序时可以直接使用现成的功能程序,这些功能程序要和用户编写的程序连接起来,形成最终计算机能够执行的机器语言程序。

? 执行 经过上述三步之后生成的机器语言程序,在Turbo C系统中称为目标程序,把目标程序

1

交给计算机,计算机在操作系统的支持下,就能按人的要求实现相应的功能,就是执行程序,并把执行的结果输出在输出设备上,供人来阅读,从而实现人机交流。

为了区别不同过程中生成的不同对象,计算机中用不同的文件扩展名来表示,编程阶段生成的文件扩展名是.c,编译阶段生成的文件扩展名是.obj,连接阶段生成的文件扩展名是.exe。以上过程可用图1.1表示。

键盘输入 编程 .c 编译 .obj 连接 .exe 执行 输出结果

图1.1 人机交流的过程

3.C语言程序的基本结构

下面通过几个C语言程序的实例,介绍C语言程序的基本构成和书写格式。 【例1-1】已知圆的半径,请编程求圆的面积。

/*求圆的面积*/

#include main() {

float r,s; /*定义变量r,s表示圆的半径和面积*/ r=5.365; /*给半径赋值*/ s=3.14*r*r; /*计算面积*/ printf(“s=%f\\n”,s); /*输出面积*/ }

【例1-2】请编程求两个整数中的大数。

/*求两个整数中的大数*/ #include main() {

int num1,num2,m; /*定义变量num1,num2和m*/ scanf(“%d%d”,&num1,&num2); /*输入两个整数*/

m=max (num1,num2); /*调用max函数求大数存入m变量*/ printf(“max=%d\\n”,m); /*输出大数*/ }

/*用户设计的函数max*/

int max(int x,int y) {

if(x>y)

return x; /*比较返回大数*/ else

return y;

}

结合以上示例,可见C语言程序由以下几部分组成:

1. C语言程序由函数组成,每个函数完成相对独立的功能,函数是C语言程序的基本模块单元。main和max是函数名,x,y是函数max的形式参数;

2. 一个C语言程序总是从main函数开始执行,main函数执行结束,程序执行即结束; 3. C语言程序的开头部分一般是编译预处理命令(如#include,#define命令)和全局变量的定义语句。

4.C语言程序的书写格式

2

1. C语言的语句以分号“;”作为语句结束标志;

2. 每行通常写一条语句,一行也可写多条语句,长语句也可分在多行书写;

3. 为了使程序更加清晰,便于阅读,采取缩进书写格式,不同一层次的语句依次缩进两个字符或者一个水平制表符;

4. 注释由“/*”开始,由“*/”结束; 5. 复合语句由“{}”括起来; 6. 编译预处理命令后不加“;”。

5.人机交流过程的演示(TC集成调试环境的使用)

Turbo C 是美国Borland 公司的产品,Borland公司是一家专门从事软件开发、研制的大公司。该公司在1987年首次推出Turbo C 1.0 产品,其中使用了全然一新的集成开发环境,即使用了一系列下拉式菜单,将文本编辑、程序编译、连接以及程序运行一体化,大大方便了程序的开发。Turbo C 2.0 则是该公司1989年出版的,Turbo C 2.0在原来集成开发环境的基础上增加了查错功能,并可以在Tiny模式下直接生成.com (数据、代码、堆栈处在同一64K 内存中) 文件,还可对数学协处理器 (支持8087/80287/80387等)进行仿真。使用Turbo C 2.0可以进行C语言源程序的编辑、编译、连接和运行,方便用户程序的调试。

5.1 Turbo C 2.0基本配置要求

Turbo C 2.0可运行于IBM-PC系列微机,包括XT,AT及IBM 兼容机。 此时要求DOS 2.0或更高版本支持,并至少需要448K的RAM,可在任何彩、单色80列监视器上运行。支持数学协处理器芯片,也可进行浮点仿真,这将加快程序的执行。

5.2 Turbo C 2.0的启动

在DOS系统下Turbo C 2.0安装完毕,将在C盘根目录下建立一个TC子目录,TC下还建立了两个了目录LIB和INCLUDE,LIB子目录中存放库文件,INCLUDE子目录中存放所有头文件。运行Turbo C 2.0时,只要在TC子目录下键入TC并回车即可进入Turbo C 2.0集成开发环境。

5.3 Turbo C 2.0窗口介绍

进入Turbo C 2.0集成开发环境中后,屏幕上显示如图1.2的TC工作窗口。

其中顶上一行为Turbo C 2.0 主菜单,中间窗口为编辑区,接下来是信息窗口,最底下一行为参考行。这四个窗口构成了Turbo C 2.0的主屏幕,以后的编程、编译、调试以及运行都将在这个主屏幕中进行。

5.4 C语言程序的编辑 1.编辑一个新文件

3

如果要输入或编辑一个新的C语言程序,应该先选File菜单,然后选择子菜单new,编辑窗口被

主菜单 编辑区 信息窗口 参考行 图1.2 TC工作窗口

清空,光标定位在左上角(Line 1、Col 1),这时注意默认的文件名为“NONAME.C”。

用户可以开始输入和编辑源程序了。输入和编辑程序的操作类似于通常的字处理软件,通过Insert键进行插入和改写状态的切换,如果有“Insert”显示,表示处于插入状态。程序输入完毕要及时进行保存,保存文件操作应选择File菜单的子菜单Save,这时会弹出一个对话框如图1.3所示,要求用户输入文件名及其路径来修改默认的路径和文件名。注意文件的扩展名“.c”不可省略。一旦用新的文件名保存文件后,编辑窗口默认的文件名“NONAME.C”被改为新的文件名。

2. 编辑一个已存在的文件

如果要重新编辑一个已经存在的文件,应选择File菜单下的子菜单Load,这时会弹出一个类似于图1.3的对话框,当用户输入要打开的文件名和路径后,即打开了此文件,这时用户就可对其进行重新编辑并保存。编辑窗口这时会显示打开的文件名。

3.重命名一个文件

如果要对正在编辑的文件重命名,请选择File菜单下的子菜单Write to,这时会弹出一个同样类似图1.3的对话框,要求用户输入新的文件名和路径。完成之后编辑窗口将以新的文件名显示。 5.5 C语言程序的编译和连接

编辑好源程序并存盘后,应当对源程序进行编译、连接和运行。在Turbo C集成环境中,进行编译、连接和运行是十分方便的,既可以将编译、连接和运行分三个步骤进行,也可以将编译和连接合起来作为一步进行,然后再运行;还可以三者合在一起一次完成。既可对单个模块的程序进行编译、

4

图1.3

图1.4

连接和运行,也可以一次对多个文件模块的程序进行编译、连接和运行。

1.对单文件程序的编译和连接

(1) 编译 选择Compile菜单下的子菜单Complie to OBJ,此时系统显示默认的目标文件名。编译后,目标文件将保存在当前工作目录或配置文件TCCONFIG.TC所指定的输出目录中。

(2) 连接 有了目标文件后,还不能直接运行,还要将目标文件与系统提供的库函数和包含文件等连接成一个可执行文件(扩展名为.exe),才能运行这个.exe文件。选择Compile菜单的子菜单Link EXE file,就可执行连接操作,在当前工作目录或者配置文件TCCONFIG.TC所指定的输出目录中生成一个可执行文件。应注意的是,必须是在编译没有错误的情况下才能进行连接。

(3)一次完成编译和连接 选择Compile菜单下的子菜单Make EXE file,即可一次完成编译和连接,从而在当前工作目录或者配置文件TCCONFIG.TC所指定的输出目录中生成一个目标文件和一个可执行文件。

注:在选择相关菜单时,请注意有些菜单后面跟有快捷键提示,也就是说可以直接按对应的快捷键实现菜单的功能。如进行存盘操作,需要选择File菜单的子菜单Save,也可以直接按F2键,相当于进行了上面的选择。

2.对多个程序文件进行编译和连接

如果一个源程序包含多个文件模块,则应当对各文件分别进行编译,得到多个目标文件,然后将这些目标文件和库函数、包含文件等连接成一个可执行文件。Turbo C提供了多个程序文件进行编译和连接的简便方法,即将这些文件组成一个“项目”,为此要建立一个“项目文件”,以.prj作为扩展名,项目文件中包含这些文件,然后将该项目文件交付编译和连接,就可以得到可执行文件了。具体步骤如下:

(1)在Turbo C 编辑环境中,输入各源文件名,如有两个文件需要进行编译和连接,则.prj文件内容见图1.4所示。

(2)将上述编辑的内容保存成项目文件。选择File菜单的子菜单Save或Write to,输入项目文件名包括路径,并且注意一定要包含扩展名.prj,以表示建立的是项目文件。

(3)建立项目。选择Project菜单的子菜单Project name,输入刚建立的项目文件名。 (4)编译和连接。选择Compile菜单下的子菜单Make EXE file,系统就会对此项目文件进行编译和连接,并生成两个目标文件和一个可执行文件,生成的可执行文件名同项目文件名。

注:在选择Make EXE file菜单进行编译和连接时,系统首先查找有无项目文件,如果在Project name中指定了项目文件,则系统优先编译该项目文件,而不是编译编辑窗口中的文件。应特别注意,在处理完一个多程序文件的编译和连接后,应及时将Project name清空,否则就会在编译连接时仍然把项目文件当做编译对象,而不是编译编辑窗口中的源文件。

5

3. 编译和连接过程中的显示信息

图1.5

(1)编译过程中出现的信息如图1.5所示,窗口最上方的Compiling表示是编译阶段的信息;第一行表示编译的主文件是HELLO.C;第二行正在编译的是正在编辑的文件HELLO.C;接下来表示编译的行数是220,警告0个,错误1个;下面一行表示占用的存储空间为299KB;最后一行表示编译成功(Success)或者有错误(Errors),请用户按任意键继续。需要解释的是,只有编译没有错误时,才可以进行连接,否则仍需要进行编辑,再编译。

(2)连接过程中出现的信息如图1.6所示,连接过程出现的信息和编译的信息类似,只有警告和错误都为0,才表示连接成功,并且最下面也有文字提示Success。只有连接成功才能生成可执行文件。

图1.6

5.6 C语言程序的运行

经过成功的编译和连接之后,就生成了可执行文件,这时就可以运行了。运行一个程序,可采用以下几种方法:

1. 在TC的集成环境中运行

6

选择Run菜单下的子菜单Run,即可运行程序。

2. 在DOS环境下运行

在DOS提示符下,输入可执行文件的文件名和路径,即可运行程序。

3. 在WINDOWS环境下运行

(1)选择WINDOWS开始菜单中的运行子菜单,然后输入文件名及路径。 (2)在资源管理器中双击所生成的可执行文件名。

5.7 在TC集成环境中查看运行结果

在TC集成环境中有一个用户屏幕(User Screen),程序运行结果将显示在用户屏幕,从编辑窗口切换到用户屏幕,选择Run菜单下的子菜单User Screen,或用快捷键Alt+F5即可进入用户屏幕,从用户屏幕按任意键即可进入编辑窗口。

6.C语言学习要求

1.按时上课及上机;

2.勤于思考,多查阅资料; 3.多进行实践; 4.具有团队协作精神; 5.分组学习。

7.实验一 TC集成调试环境的初识

7.1 实验目的

1. 熟悉TC集成调试环境;

2. 掌握在TC环境下编辑、编译、连接和运行C语言程序的过程; 3. 熟悉C语言程序的组成及书写格式。

7.2 实验要求

1. 普通微机; 2. TC集成调试环境。

7.3 实验内容及步骤

1. TC集成调试环境的熟悉

1.1启动TC集成调试环境; 1.2熟悉各菜单项; 1.3熟悉各功能键;

1.4熟悉编辑窗口各部分的意义; 1.5退出TC集成环境。

2. 调试【例1.1】程序并记录相关信息

2.1输入【例1.1】程序,输入时省略注释部分。 源程序:

2.2用program1.c文件名保存文件在自己的目录下。

2.3编译program1.c源程序文件,生成program1.obj目标文件(该步可能需要反复进行)。 编译提示信息: 修改情况记录:

错误原因分析:

7

2.4连接程序,生成可执行文件program1.exe(2.3和2.4两步可能需要反复进行)。 连接提示信息: 修改情况记录:

错误原因分析:

2.5执(运)行program1.exe文件,记录输出结果。 运行结果:

2.6修改【例1.1】程序,求半径为6.2圆的面积,重复2.1~2.5步骤,并记录每一步相关信息。

3. 调试【例1.2】程序并记录相关信息,用program2.c文件名保存源程序。调试步骤同2. 。 4. 编程求5!,并调试该程序,记录每一步相关信息。

7.4思考题

1. 请总结C语言程序调试的步骤。

2. 为什么程序修改后需要重新进行编译、连接和运行? 3. TC为什么称为集成调试环境?

8.课后练习(要求所有程序必须上机运行通过)

1. 模仿讲议中C语言程序,编写程序求圆的周长。

2. 模仿讲议中C语言程序,编写程序求两个整数中的小数。 3. 上机运行下列程序,并记录输出结果。

#include main() {

printf(“Hello C program world !\\n”); printf(“I am an university student !\\n”); }

4. 请参照第3题的程序,编程输出下列图形。

*

* * * * * * * * * * 5. 请参照第4题的程序,编程输出下列图形。(可选做)

* * *

* *

* * * * * * * * *

6. C语言程序由哪几部分组成?其程序的基本单位是什么?

9.补充阅读

9.1计算机语言的发展过程

1.第一代语言----机器语言(低级语言)

机器语言是由0、1组成的机器指令集合,是面向机器的语言。

要使计算机按人的意图工作,就必须使计算机懂得人的意图,接收人向它发出的命令和信息。人要和机器交换信息就要解决一个“语言”的问题。计算机并不懂人类的语言(无论是中文或英文),例如,我们要写y=2x+3,机器不能接受。它只能识别0和1两种状态,如光电输入机中纸带有孔的地

8

方代表1,无孔的地方代表0。由0和1组成各种排列组合,通过线路转变成电信号,让计算机执行各种不同的操作。

这种直接用0和1 组成的机器指令编写程序,就是机器语言源程序。对计算机来说,这是它唯一能直接读懂的语言,所以,通常称之为机器语言。但是,对于使用计算机的人来说,这是十分难懂的语言,它难读、难记、难写,容易出错,不同的机型又不通用,显然人和机器之间的通信存在巨大的鸿沟,只有填补上这个鸿沟,才能让用户使用起来方便容易,机器又能懂,计算机才能发挥更大的作用,为此,人们研究了一种汇编语言。

2.第二代语言----汇编语言(低级语言)

汇编语言也叫符号语言,它是把用二进制数表示的指令,用一些符号来表示,例如,用表示操作的英文缩写来代替汇编语言指令代码。下面是一段汇编语言代码。

LDA A 取出A

ADD B A和B相加 STA C 存入C PRINT C 打印C STOP 停止

这种用符号代替二进制代码的指令,就叫汇编语言。像LDA、ADD这类符号称之为指令符号或助记符。用汇编语言编写的程序,称为汇编语言程序。

这种语言,相对于机器语言来说容易读、容易记,但是,机器却不能识别。因此,计算机是无法执行的。为了让机器能执行汇编语言程序,这时就需要一个翻译,正如一个不懂汉语的外国人到中国来无法同中国人直接交流,需要借助于翻译一样,借助于翻译,将汇编语言程序翻译成机器语言程序,这个翻译过程叫做“汇编”。汇编后产生的机器代码称为目标程序。翻译可由人手工完成,也可用计算机来完成,用计算机来做翻译,实际上是研制了翻译程序,把这个翻译程序称为汇编程序。汇编过程如图1.7所示。

汇编程序 (事先放入计算机) 汇编语言 (输入) 源程序 (汇编) 机器指令 目标程序 (执行) 计算机执行 结果输出 图1.7 汇编过程

汇编语言使程序设计工作前进了一大步,但是仍然存在很多缺点:第一,不便于我们求解问题过程的描述,如一个数学公式,汇编语言的表达式与人们的习惯表达形式差距很大;第二,它仍然是面

向机器的语言,不同机型,汇编语言也不一样,因此用它编制程序,没有通用性。为了克服这些不足之处,人们进一步研制开发出了高级语言。

3.第三代语言----算法语言(高级语言)

算法语言是更接近人的自然语言和数学表达式的一种语言,由表达不同意义的“关键字”和“表达式”按照一定的语法语义规则组成、完全不依赖机器的指令系统。这样的高级语言为人们提供了很大的方便,编制出来的程序易读易记,也便于修改、调试,大大提高了编制程序的效率和程序的通用性,便于推广交流,从而极大地推动了计算机的普及与应用。常见的BASIC、FORTRAN、ALGOL、COBOL、C等都是高级语言。

高级语言更接近人的习惯,便于人的理解与使用,可计算机却更难理解与接受,计算机不能直接理解那些英语单词、数学表达式。所以,为了填补计算机和人之间的鸿沟,还得求助于翻译。这种翻译通常分为两种形式,一种叫解释方式,另一种叫编译方式。

编译方式是事先编好一个称为编译程序的机器指令程序,并放在计算机中,把用高级语言编写的

9

源程序输入计算机,编译程序就把源程序整个翻译成用机器指令表示的目标程序,然后执行该目标程序,得到计算结果。其过程如图1.8所示。

编译程序 (事先放入计算机) 高级语言 (输入) 源程序 (汇编) 机器指令 目标程序 (执行) 计算机执行 结果输出 图1.8 编译过程

解释方式是事先编好一个称为解释程序的机器指令程序,并放在计算机中,把用高级语言编写的源程序输入计算机,它并不像编译方式那样把源程序整个翻译成用机器指令表示的目标程序,而是逐

句地翻译,译出一句立即执行,即边解释边执行。其过程如图1.9所示。

C语言采用的是编译方式。

高级语言的用户可以完全不顾机器指令,也不必深入懂得计算机内部结构和工作原理,就能方便地使用高级语言编写程序进行各种科学计算和事务处理,并且由于采用编译(解释)程序代替人工翻译,大大降低了人们的工作量,因此,有人说,高级语言的出现是计算机发展中“最惊人的成就”。

目前,世界上已有100多种高级语言,比较流行的有几十种之多,比如:

? FORTRAN(Formula Translator的缩写)语言是世界上最早出现的高级语言,从1954年问世

以来,经过几次大的发展,功能有很大的增强,它特别适用于科学计算和工程计算。

? COBOL(Common Business Language的缩写)语言适用于非数值计算的商业、管理领域。 ? PASCAL语言是最早出现的结构化语言,适用于计算机教学。

? PL/1语言是一种大型语言,功能强,适用于数值计算和数据处理。 ? Ada语言是一种工程化的大型语言,适用于大型软件工程。 ? C语言是近年来广泛推广的结构化语言,适用于编写系统软件。 ? BASIC语言是一种简单会话式语言,在世界上应用最广泛。

4.第四代语言----非过程化语言(高生产率语言)

非过程化语言就是目前比较流行的面向对象语言,该语言只需要编程人员对问题进行描述。比如C++/Visual C++,JAVA语言等。

解释程序 (事先放入计算机) 高级语言 (输入) 源程序 (解释并执行) 计算机执行 结果输出 图1.9 解释过程

目前也出现了智能化语言,主要用于人工智能等领域。比较有代表性的有LISP语言和PROLOG语言。

9.2 C语言的特点

C语言是一种出现比较晚的高级语言,它吸取了早期高级语言的长处,克服了某些不足,形成了自己的风格和特点。总的来说,C语言是一种简洁、功能强大、可移植性好的结构化程序设计语言。C语言具有如下特点:

10

? C语言简洁、紧凑;

? C语言是一种结构化程序设计语言; ? C语言具有丰富的数据类型; ? C语言提供了丰富的运算符;

? C语言可以直接对硬件进行操作;

虽然C语言具有灵活简炼的特点,但在有些方面也存在不足,了解其不足有助于使用,避免出现错误。其不足简单概括如下:

? 运算符多,难于记忆;

? C语言类型转换比较灵活,在许多情况下不做检查,对类型要求不够严格;

? C语言中对数组进行初始化主要是判定是否越界,越界时会发生编译错误,但在动态赋值时

不判定越界,这样容易造成数据存储方面的混乱。 总之,C语言有诱人的优点,也有值得注意的不足,使用时应特别加以注意。

11

模块二 C语言程序设计入门

能力标准:

1. 能编写、分析基本的C语言程序;

2. 熟练掌握程序的多种调试方法。 知识点:

1. 基本数据类型;

2. 3.

各种运算符及表达式; 三种基本的程序结构。

案例一 一个经典C语言入门程序

—helloworld.c

教学目的:

1. 巩固C语言程序结构;

2. 掌握printf函数输出字符串的功能; 3. 掌握clrscr函数的功能与使用;

4. 熟悉用编译预处理命令#include命令包含头文件。

在模块一中,我们已经知道C语言程序由函数构成,并且任何一个程序有且只有一个main函数,程序的执行总是从main函数开始的,由main函数的第一条语言开始执行,到main函数的最后一条语句结束。下面是一个最简单的C语言程序,我们将对该程序的每一行进行分析。

/* Hello world! */ #include main() {

printf(“Hello world!\\n”); }

一、案例分析

1.“/*Hello world!*/”行是一个注释行,用来说明该段程序的功能。一般如果在程序的开头加上这样的注释行,便于用户阅读与分析程序。注释可以用中文或英文,如果操作系统是英文的,则中文字符在编译时是不认识的符号,建议使用英文注释,便于和国际接轨。

2.“#include ”行是一个编译预处理命令行,其中“#include”是编译预处理命令,其作用是将一个C语言源程序文件的全部内容包含到当前这段程序中,“”是指定被包含的文件。一个#include命令只能包含一个文件,需要多个文件包含时,必须用多个#include命令。#include命令行应放在程序的开头位置,故有时也把被包含的文件称为头文件,常以“.h”作为扩展名(后缀),如stdio.h文件,事实上可以用“.c”或其它的扩展名。

被包含文件可以用双引号和尖括号括起来,其区别在于用尖括号时,系统先到存放C库函数头文件所在的目录寻找要包含的文件,称为标准方式;用双引号时,系统先在用户当前目录中寻找要包含的文件,若找不到,再按标准方式查找。一般地,如果是调用库函数而用#include命令来包含相关的

12

头文件时,用尖括号,以节省查找时间;如果要包含的是用户自己编写的文件(通常存放在当前目录中),则用双引号。 stdio.h文件是C语言的标准输入输出头文件,该文件主要是对输入输出函数进行定义。例如printf函数、scanf函数、getchar函数、putchar函数。

3.从“main()”行开始,直到“}”为止是主函数main的定义部分。其中“main()”行是函数定义的头(首)部,用于说明函数返回值的类型、函数名及形式参数的定义。主函数main是一个特殊的函数,它的首部标准格式是 [int] main([int argc,int *argv[]]),用“[]”括起来的部分表示是可选项,“int”说明main函数的返回值是整型,“main”是函数名,“int argc,int *argv[]”是main函数的形式参数定义,“()”是函数定义不可缺少的部分。在目前我们的使用中只需要使用main函数最简单的定义形式,即“main()”。从“{”起到“}”止是函数的实现部分,也就是实现函数功能的语句组合,通常称为函数体。因此函数的通常定义格式如下:

[函数返回类型] 函数名( [形式参数定义]) /*函数的首部*/ {

函数体; /*函数的实现部分*/ }

本例中的main的函数体只有一条语句,即“printf(“Hello world!\\n”);”,其作用是向输出设备输出字符串“Hello world!”。

二、C语言函数简介

C语言函数分为库函数和用户自定义函数两类,库函数由系统提供,编程者只需要直接使用,用户自定义函数需要编程者自己编写。比如我们前面见过的printf函数就是库函数,main函数就是用户自定义的函数。

任何一个函数都需要先定义,然后被调用。函数的定义同上述main函数的定义,函数的调用格式如下:

函数名(实际参数)

对于库函数printf,其定义包含在stdio.h头文件中,因此我们要使用它时,需要用#include命令把stdio.h文件包含到当前的程序中,然后才能调用printf函数。printf函数的一种调用格式如下:

printf(“字符串”)

其作用是将“字符串”输出到显示器上,对上例来说就是将“Hello world!”输出到显示器上,显示器上将显示“Hello world!”字符串。请注意“\\n”字符的作用是换行,即下一个printf函数的输出内容将另起一行。字符串在计算机中是指用双引号括起来的一串字符序列,如“1234”、“student”。

三、显示学生管理系统的主菜单

在未讲到C语言图形函数时,我们所设计应用程序的用户界面都是字符型的。如一个学生管理系统,我们需要提供以下的主菜单界面,供用户根据菜单选择相应的功能,从而调用对应的函数。

13

****student management system menu**** * 1. Input student records * * 2. Output student records * * 3. Insert a new student * * 4. Delete a student * * 5. Find a student on name or number * * 6. Sort on score * * 7. Save to file * * 8. Import file * * 0. Exit * * Please input your choice(0~8): * *******************************************

根据上述要求,我们需要编程输出这样的菜单,通过我们已学的知识,可以写一个主函数,函数体就是用printf输出每一行即可。程序如下:

/*学生管理系统输出主菜程序*/ #include main() {

printf(“****student management system menu****\\n”); printf(“* 1. Input student records *\\n”); printf(“* 2. Output student records *\\n”); printf(“* 3. Insert a new student *\\n”); printf(“* 4. Delete a student *\\n”); printf(“* 5. Find a student on name or number *\\n”); printf(“* 6. Sort on score *\\n”); printf(“* 7. Save to file *\\n”); printf(“* 8. Import file *\\n”); printf(“* 0. Exit *\\n”); printf(“* Please input your choice(0~8): *\\n”); printf(“*******************************************\\n”); }

通过这个实例我们可以看到,在实际应用中,要输出系统菜单,主要是调用printf函数,一行一行输出字符串。

四、clrscr函数

如果在TC系统中,重复执行上例程序,可以看到显示器上连续重复显示主菜单,而实际使用中我们希望不管理执行多少次,主菜单总是显示在屏幕的上方。为此我们需要在主菜单显示前,先擦除原来的屏幕,然后再输出主菜单,这样不管重输出多少次,主菜单总是在屏幕上方。擦除屏幕,可以调用库函数clrscr函数,它的定义在conio.h头文件中,因此将前述的程序作如下修改如下(斜体部分): 斜体部分是新增加的语句行,“#include ”行是将clrscr函数的定义文件包含进当前程序,“clrscr();”行是通过调用库函数clrscr擦除当前屏幕,该函数没有参数,也不需要返回值。

五、实验二 printf和clrscr函数

5.1实验目的

1. 进一步熟悉TC集成调试环境; 2. 熟悉C语言程序的构成; 3. 熟悉C语言函数的定义; 4. 掌握用printf函数输出字符串; 5. 熟悉clrscr函数。

14

/*学生管理系统输出主菜程序*/ #include #include main() {

clrscr();

printf(“****student management system menu****\\n”); printf(“* 1. Input student records *\\n”); printf(“* 2. Output student records *\\n”); printf(“* 3. Insert a new student *\\n”); printf(“* 4. Delete a student *\\n”); printf(“* 5. Find a student on name or number *\\n”); printf(“* 6. Sort on score *\\n”); printf(“* 7. Save to file *\\n”); printf(“* 8. Import file *\\n”); printf(“* 0. Exit *\\n”); printf(“* Please input your choice(0~8): *\\n”); printf(“*******************************************\\n”); }

5.2实验内容及步骤

1.调试“Hello world!”程序,并做以下记录。 程序:

编译结果: 修改记录: 运行结果:

2.连续运行三次上述程序,记录输出结果。 运行结果:

3. 如果去除printf(“Hello world!\\n”);语句中的“\\n”,请连续运行三次,记录输出结果,并与2.1.1运行结果进行比较,分析不同的原因。

4. 调试“学生管理系统输出主菜”程序,并记录 程序:

编译结果: 修改记录: 输出结果:

5.连续运行三次,记录输出结果。

输出结果:

6.调试添加clrscr函数后的“显示学生管理系统主菜单”程序,连续运行三次,记录结果并与5运行结果比较,分析输出结果不同的原因。

输出结果:

7.编程输出下图。

* * *

* * * * * * *

程序:

编译结果: 修改记录: 输出结果:

5.3思考题

(1)clrscr函数有没有将屏幕全部擦干净?为什么有时屏幕的下部擦不干净?

15

六、习题

1. 编程输出下列图形。

********常州轻工职业技术学院学生成绩表******** 学号 姓名 班级 语文 数学 英语 政治 计算机 总分 名次

8 88 888 8888 (a)

8 888 88888 8888888 (b)

8 88 888 8888 (c)

88 88 88 88 (d)

2. 请编程输出下列表头。

16

案例二 求任意两个数之和(差、积、商)

教学目的:

1. 掌握整型和实型变量的定义;

2. 掌握整型和实型变量的数据范围; 3. 掌握用scanf函数输入整型和实型数据; 4. 掌握用printf函数输出整型和实型数据。

C语言将数分为整型和实型两种类型,不同的类型,在程序编写上有所区别,因此案例二要求的两个整数之和,我们先给出求两个整型数据和的程序,如下:

/*求两个整数的和*/ #include #include main() {

int num1,num2,sum; /*定义三个整型变量*/ clrscr(); /*清除屏幕*/

sum=0; /*和的初值置为0*/

printf(“Please input two integers:”); /*显示提示字符*/ scanf(“%d”,&num1); /*输入第一个整数*/ scanf(“%d”,&num2); /*输入第二个整数*/

sum=num1+num2; /*求两个整数的和,并存入变量sum中*/ printf(“num1 and num2 is: %d\\n”,sum); /*输出和值*/ }

一、案例分析

1. 上述程序的功能是通过键盘输入两个整数,然后求两个整数的和。这段程序也只有一个主函数。

2. “int num1,num2,sum;”行根据注释可知是定义了三个整型的变量。

? 变量 就是如同数学中用到的x、y等,可以改变它们的值,在C语言中给变量取名字时要

求只能用数字、字母和下划线组成,且第一个符号不能是数字。如“_sum,num,score”等

都是合法的变量名,而“1a,2_b”等是不合法的变量名。

? 常量 如123,-7,34.6,-0.76等都是常量,前两个称为整型常量,后两个称为实型常量。 ? 整型变量的定义 C语言中整型变量又分为基本整型(int)、短整型(short int 或short)、长

整型(long int 或long)及无符号整型(unsigned int、unsigned short int/ unsigned short、unsigned

long int/ unsigned long)。如: int num1,num2,sum; 表示定义了三个基本的整型变量; short a;或者short int a;表示定义了短整型变量a;

long int c;或者long c;表示定义了长整型变量c; unsinged int d;表示定义了基本的无符号整型变量d;

各种整型变量在不同的计算机机型中存放的数的范围不同,也即表示数所用的字节数不同,

见表2-1。

表2-1 整型变量所占用字节数和数的范围

数据类型 int

所占字节数(二进制位数) 2(16) 17

数的范围 -32768~32767 即-215~(215-1) short int /short long int /long unsigned int unsigned long int/ unsigned long 2(16) 4(32) 2(16) 4(32) -32768~32767 即-2~(2-1) -2147483648~2147483647即-231~(231-1) 0~65535即(0~216-1) 0~65535即(0~216-1) 0~4294967295即0~(2-1) 321515unsigned short int/ unsigned short 2(16) 3. “ sum=0;”行是给存放和值的变量赋初值0。

4. “printf(“Please input two integers:”);”行是在屏幕上输出“Please input two integers:”字符串,以提示用户输入两个整数。

5. “scanf(“%d”,&num1);”行的作用是等待用户从键盘输入一个整数,并存入变量num1中。 ? scanf函数 scanf函数是标准库函数,其作用是等待用户从键盘给变量输入值。scanf函数的定义包含在stdio.h头文件中。 ? scanf函数调用格式

scanf(格式串,地址列表)

“%d”就是格式串,其表示的意思是等待从键盘输入的必须是一个整型数据。scanf函数的格式串是由“%”开始,其后跟不同的类型格式符。具体格式符见表2-2。

表2-2 scanf函数的格式符 格式符 d,i u o X,x c s f e 输入有符号十进制整数 输入无符号十进制整数 输入无符号八进制整数 输入无符号十六进制整数(大小写作用相同) 输入单个字符 输入字符串,将字符串送到一个起始地址起的存储单元中,输入时以非空格字符开始,以第一个非空格字符结束。字符串存储时以‘\\0’作为结束标志 输入实数,可以是小数形式及指数形式 与f作用相同,可以互换 “&num1”表示一个地址,这个地址就是变量num1在内存中分配的存储单元的首地址,“&”在变量名前表示取该变量的地址。如果是地址列表,则各地址之间用“,”隔开。

“scanf(“%d”,&num2);”行同“scanf(“%d”,&num1);”行的作用,等待用户从键盘给变量num2输入值。

上述两条语句也可合并为一条语句scanf(“%d%d”,&num1,&num2); ,这时在输入两个数据时,可以用空格、回车或制表符进行分隔。 6.“sum=num1+num2;”行是求num1和num2两个变量值的和,并把和存入变量sum中。 7. “printf(“num1 and num2 is: %d”,sum);”行的作用是输出变量sum的值。这里我们见到了printf函数的第二种调用形式:printf(“控制字符串”,输出项列表)

? 格式串 printf函数的控制字符串包括格式串和普通字符串,其格式串也是以“%”开始,后

跟相应的格式符。printf函数的格式符见表2-3。

表2-3 printf函数的格式符 格式符 d,i u o X,x

说 明 说 明 以带符号的十进制形式输出整数(正数不输出符号) 以无符号十进制形式输出整数 以八进制无符号形式输出整数(不输出前导符0) 以十六进制无符号形式输出整数(不输出前导符0 x),用x则在输出十六进制数的a-f18

时以小写形式输出;用X时,则以大写字母输出 c s f E,e G,g 以字符形式输出,只输出一个字符 输出字符串 以小数形式输出单、双精度型数,隐含输出6位小数 以指数“e”或“E”形式输出实数(如1.2e+02或1.2E+02) 选用%f或%e格式中输出宽度较短的一种格式,不输出无意义的0,用G时,若以指数形式输出时,则指数以大写表示 is: %d”,sum);语句中“num1 and num2 is:”是普通字符串,因此是原样显示,并且“num1 and num2 is:”是在%d之前,因此先输出“num1 and num2 is:”,然后输出sum变量的值,%d表示输出整型数据项。 8.案例运行结果

运行时如果输入:34回车 62回车 输出结果:num1 and num2 is:96

? 普通字符串 在printf函数中,普通字符串根据其顺序,原样显示。如printf(“num1 and num2 二、应用举例

上述案例是求两个整型数据的和,如果要求的是两个实数的和,应如何编写程序呢? 【例2-1】请编程求两个实数的和。

? 分析 C语言将数分为整型数和实型数,前面已经讲述了整型变量的定义方法,本例要求两

实数的和,同样也需要事先定义实型变量,然后再求和。其编程方法同求整数和一样,只是现在的对象是实数。

? 实型变量的定义 C语言中实型变量分为两种类型,分别是单精度(float)和双精度(double)。

如float x; 表示定义了单精度类型变量x;double y;表示定义了双精度类型变量y。两种实型

数据占用的存储字节数和表示的数的范围是不同的。其中float型占4个字节(32个二进制位),表示数的范围是:-3.4e-38~3.4e+38,但只能提供7位有效数字;double型占8个字节(64个二进制位),表示数的范围是:-1.7e-308~1.7e+308,可提供16位有效数字。 ? 修改案例程序(1)变量类型由int改为float; (2)scanf和printf函数的格式符由%d改为%f。 ? 程序

/*求两个实数的和*/ #include #include main() {

float f_num1,f_num2,f_sum; /*定义三个实型变量*/ clrscr(); /*清除屏幕*/

f_sum=0; /*和的初值置为0*/

printf(“Please input two reals:”); /*显示提示字符*/ scanf(“%f”,&f_num1); /*输入第一个实数*/ scanf(“%f”,&f_num2); /*输入第二个实数*/

f_sum=f_num1+f_num2; /*求两个实数的和,并存入变量f_sum中*/ printf(“f_num1 and f_num2 is: %f\\n”,f_sum); /*输出和值*/ }

【例2-2】请编程求两个实数的差。

本例只需要将例2-1程序中语句“f_sum=f_num1+f_num2;” 中的“+”改为“-”即可。 【例2-3】请编程求两个实数的商及积。 本例同例2-2,修改一下运算符即可。

19

【例2-4】请编程求两个整数的商。

根据前面的例题,我们自然可以很轻松地将案例程序中的“+”改为“/”即可。程序如下: /*求两个整数的商*/ #include #include main() {

int num1,num2,sum; /*定义三个整型变量*/ clrscr(); /*清除屏幕*/

sum=0; /*和的初值置为0*/

printf(“Please input two integers:”); /*显示提示字符*/ scanf(“%d”,&num1); /*输入第一个整数*/ scanf(“%d”,&num2); /*输入第二个整数*/

sum=num1/num2; /*求两个整数的商,并存入变量sum中*/ printf(“num1 divide num2 is: %d\\n”,sum); /*输出商值*/ }

运行上述程序,如果输入:16回车 4回车

则输出结果为:num1 divide num2 is:4 如果输入:16回车 5回车

则输出结果:num1 divide num2 is:3

结果分析:C语言规定两个整数相除的结果还是整数,所以16除5的结果是3。

三、小结

1. 求两个数的和、差、积、商程序的思路是,根据实际需要先定义所需类型的变量,然后计算

和、差、积、商,最后输出计算结果。通常程序的编写也遵循这样的三步曲:先定义变量,

然后进行相应的处理,最后将处理结果输出。

2. C语言规定,所有的变量一定要先定义,然后才能使用。

3. C语言的变量有类型之分,而且分得比较细,要根据需要选择不同的类型。

4. printf和scanf这两个库函数,定义了多种格式,需要针对不同的对象选择不同的格式符。

四、实验三 求两个数和、差、积、商

4.1实验目的

1. 掌握整型、实型变量的定义方法;

2. 掌握printf和scanf函数的%d和%f格式控制符; 3. 熟悉实型、整型变量所表示数的范围。 4.2实验内容及步骤

1.运行案例程序,并记录相应过程。 程序:

编译结果: 修改记录: 输入数据: 运行结果:

2.调试【例2-1】的程序,并记录相关数据。 程序:

编译结果: 修改记录:

20

输入数据: 运行结果: 3.分别调试【例2-2】、【例2-3】的程序,并做好记录。 编译结果: 修改记录: 输入数据: 运行结果:

4.调试【例2-4】的程序,输入讲义中的数据,观察并记录,自己再准备两组不能完全整除的数据,记录结果,并分析为什么结果不精确。 编译结果: 修改记录: 输入数据: 运行结果: 5.编程求两个整数的积,并调试。 程序:

编译结果: 修改记录: 输入数据1:12和18 输出结果:

输入数据2:56和87 输出结果:

输入数据3:32765和3245 输出结果:

4.3思考题:

(1) 请验证2.5的实验结果,是不是每组数据输入后,输出结果都正确,如果不正确,这是为什么?

(2) 把所有printf函数中的“%f ”改为“%e”,观察并记录输出数据,分析“%f”和“%e”的功能区别。

(3) 如果把printf函数中的“%d”改为“%u”,观察并记录输出数据,分析“%d”和“%u”的功能区别。(可以选做)

五、习题(所有程序必须上机调试通过)

1. 编程求三个整数的和。

2. 根据商品原价和折扣率,编程计算商品的实际售价。 3. 已知华氏温度,编程根据公式计算摄氏温度。

摄氏温度=(华氏温度-32)*5/9

21

案例三 求多个不同类型数的和(平均值等)

教学目的:

1. 掌握整型和实型数据之间的混合运算; 2. 进一步熟悉整型和实型变量的定义。

在实际应用和,经常会碰到整型和实型数据的混合运算,例如求两个整数的平均值,精确到小数点后两位,第三位进行四舍五入。程序如下:

/*求两个整数的平均值*/ #include #include main() {

int num1,num2; /*定义两个整型变量*/ float ave;

clrscr(); /*清除屏幕*/

ave=0; /*平均值变量的初值置为0*/ printf(“Please input two integers:”); /*显示提示字符*/ scanf(“%d%%d”,&num1,&num2); /*输入两个整数*/ ave=(num1+num2)/2.0; /*求平均值,并存入变量ave中*/

ave=(int)((ave*100+0.5))/100.0; /*对平均值进行四舍五入精确到小数点后两位*/ printf(“average is: %f\\n”,ave); /*输出平均值*/ }

一、案例分析

根据实际需要,定义了两个整型变量,用于存放两个整数值,一个单精度变量ave,用于存放两个整数的平均值。

1.“ave=(num1+num2)/2.0;”行是计算两个整数的平均值,先计算num1+num2的和,和值仍为整数,然后计算num1+num2的平均值,注意此时的平均值是将和值除以2.0,而不是除以2,将计算的平均值赋给变量ave进行保存。

? 混合类型数据运算的类型转换规则 当不同类型的数据进行混合运算时,需要先把不同类型的数据转换成统一的类型,然后再进行运算。 数据类型之间的转换遵循的原则是“类型提升”,即在进行两个不同类型的量进行运算时,先将较低类型的数据转提升为较高的类型,然后在类型一致的基础上进行运算,运算结果是较高的类型。类型的高低是根据其数据所占用的存储空间大小来判断的,占用的空间赿多,类型赿高,反之赿低。具体转换规则见图2.1。

double float

long unsigned 低

int

22

char,short

图2.1 标准类型数据转换规则

图中横向向左的箭头表示必定发生的转换,如短整型(short)数据必须先转换成整型(int),单精度数据先转换成双精度型数据。纵向的箭头表示不同类型数据的转换方向。如“ave=(num1+num2)/2.0”表达式中,先进行的“num1+num2”运算,不需要进行类型转换,在进行“(num1+num2)/2.0”除法运算时,先将“num1+num2”和转换成double型,将2.0也转换成double型,然后进行运算,结果为double型,将结果赋给变量ave,这时请注意,由于ave变量是float,在赋值时,是以变量的类型为准,因此先将double类结果的转换为float类型,再赋给变量ave。

2.“ave=(int)((ave*100+0.5))/100.0;”行是实现小数点后第三位进行四舍五入的处理。处理过程如下,先把该数扩大100倍,然后加0.5,目的是进行四舍五入,第三步是对ave*100+0.5取整,取整操作是用C语言的强制类型转换符(int)进行转换,即(int)((ave*100+0.5)),实现取整运算,舍去小数部分,最后是将前面运算得到的整数缩小100倍,转换为实数,最终实现四舍五入,保留两位小数。

本案例的其余部分同前。

二、应用举例

【例3-1】假设银行定期存款的年利率rate为2.25%,并已知存款期限为n年,存款本金为capital元,试编程计算n年后可得到的本利之和deposit。(保留小数点后两位)

分析:本例存款额的计算公式为deposit=capital (1+rate)n。

pow函数:math.h头文件中的函数pow(x,y)的作用是求xy,即计算x的y次幂,其调用形式为pow(x,y),返回值为double型。对于本例(1+rate)n计算,调用pow(1+rate,n)进行计算。

程序如下:

本例中与其它程序有一个重要的区别是多了“#include ”行,其作用是把math.h头文件

n

包含进行来,目的是在程序中需要调用pow函数,来计算(1+rate)值。

/*计算整存整取的本利*/ #include #include #include main() {

int n; /*n用于存放存款年限*/ float rate, capital,deposit;

clrscr(); /*清除屏幕*/ rate=0.0225;

printf(“Please input capital and years:”); /*显示提示字符*/ scanf(“%f%%d”,&capital,&n); /*输入存款额和年限*/ deposit=capital*pow(1+rate,n);

deposit =(int)(( deposit *100+0.5))/100.0; /*对本利进行四舍五入精确到小数点后两位*/ printf(“deposit is: %f\\n”, deposit); /*输出本利值*/ }

三、习题

1.已知三角形的三条边a,b,c,请编程求三角形的面积。(需要调用math.h中的sqrt函数)

23

2.分析下列程序的执行结果。

#include #include #include main() {

int a=1,b=2,c=2; float x=10.5,y=4.0,z; clrscr();

z=(a+b)/c+aqrt((int)(y))*1.2/x+x; printf(“z=%f\\n”, z); }

3.已知一元二次方程ax+bx+c=0的三个系数a,b,c,并且该方程存在实数根,请编程求实根。

2

四、实验四 不同类型数的混合运算

4.1实验目的

? 掌握整型、实型数据的混合运算;

? 熟悉pow和sqrt函数; ? 掌握四舍五入的处理方法。 4.2实验内容及步骤

1.运行案例程序,并记录相应过程。 程序:

编译结果: 修改记录: 输入数据: 运行结果:

2.将案例中的2.0换成2,重新运行程序,记录运行结果,并分析为什么与前面的结果不同。 3.运行【例3-1】的程序,并记录相关信息。 程序:

编译结果: 修改记录: 输入数据: 运行结果: 4.调试习题1的程序。 程序:

编译结果: 修改记录: 输入数据: 运行结果: 5.调试习题2的程序。

程序:

编译结果: 修改记录: 输入数据: 运行结果:

4.3思考题 (2) 数据混合运算的转换规则有什么规律没?请总结。

(3) 查阅附录,熟悉stdio.h,math.h两个头文件所包含的函数的定义。 (4) 如果要对已知的一个实数小数点后第三位起进行舍尾处理,应如何编程?(如234.56781)

24

案例四 比较两个数的大小

教学目的:

1. 掌握关系运算符的功能; 2. 掌握基本的if……else……语句格式。

在实际应用中经常需要对两个甚至多个对象进行比较,进行某种决策。如有两个整数,需要找出其中的大数,进行输出,请编写程序。

#include

#include main() {

int num1,num2,max; clrscr();

scanf(“%d%d”,&num1,&num2);

if(num1>num2) /*比较两个数,大数存入变量max中*/ max=num1; else

max=num2;

printf(“maximum is =%d\\n”, max); }

一、案例分析

该案例中我们唯一不熟悉的语句是if??else??,其功能是首先计算表达式“num1>num2”的值,然后根据计算结果决定执行某一分支。

1. if??else??语句的基本格式

if(表达式)

{语句组1;} [else

{语句组2;}]

2. if??else??语句的执行过程

当执行到if??else??语句时,其过程如下:

计算if后的表达式;

(2) 如果表达式的值为非0,则执行语句组1;如果表达式的值为0,则执行语句组2。当else部分省略时,表达式的值为0时,什么也不做;

(3) 不管执行哪一组语句,程序接着执行if??else??语句的下一条语句。 3.if??else??语句执行过程的图形表示

称为流线,表示程序执行流向;

称为判断框,它使程序出现两个分支;

称为处理框;

(1)

25

?? 非0 计算表达式的值 0 语句组2 语句组1 ?? 图4.1 if??else??语句执行图解 根据if??else??语句的执行过程图解4.1可知,在一次执行if??else??语句时,只可能执行语句组1或者执行语句组2。在程序中,把这样的结构称为分支结构或选择结构,也即一个if??else??语句把程序分为两个分支,任何时刻只会选择其中一个分支执行。当然如果省略“else??”部分,则图4.1就没有为0 的分支,该分支变为一条流线。

4.表达式

表达式是用运算将运算量连接起来的有意义的式子,如3+5,num1+num2等。C语言中运算符非常丰富,我们已经学过的有“+”、“-”、“*”、“/”、“()”等运算符,这类运算符称为算术运算符。 4.1 运算符的优先级 当一个表达式中出现不同的运算符时,级别高的运算符先做。如算术运算符“+ - * / () ” 从左到右级别依次升高。

4.2 运算符的结合性 当一个运算对象两侧运算符的优先级相同时,这时根据运算符的结合性来决定运算次序。按“从右向左”的顺序运算,称为右结合性,按“从左向右”的顺序运算时,称为左结合性。如3+5-8表达式,其中“5”的左右两有运算符“+”和“-”,优先级相同,这时由于它们的结合性为左结合,因此“5”先与“3”进行加法运算,然后再做“-”运算。

4.3 关系运算符 是用于进行两个对象大小的比较,决定其关系的。C语言中定义的关系运算符有:“>、<、>=、<=、!、==”六种运算符,分别用于“大于、小于、大于等于、小于等于、不等于和等于”的比较,其中“>、<、>=、<=”优先级相同,“!、==”优先级相同,前四个的优先级高于后两种。

4.3.1关系运算的结果为“0”或“非0”两种,又称为“假”和“真”。如5>3的值为非0,也就是“真”;5>5的值为0,即假,5>=5的值为非0,即为真。

4.3.2关系表达式 用关系运算符连接起来的式子,称为关系表达式。如5+8==7-2,在这个关系表达式中,既有关系运算符,又有算术运算符,算术运算符优先于关系运算符,所以先进行算术运算,然后进行关系运算。(关键是注意关系运算必须是同类型的量才能进行比较,即关系运算)

5.语句组 当有多条语句组成的语句组时,语句组需要用“{}”括起来。

6.本案例中if??else??语句的执行

if(num1>num2)

max=num1;

else

max=num2;

(1)先计算关系表达式“num1>num2”的值,如果num1大于num2,则表达式的值为非

0,即真;反之为0,即假; (2)如果表达式的值为非0,则将num1的值赋给变量max,即执行“max=num1;”语句,

26

否则执行“max=num2;”语句;

(3)不管执行“max=num1;”还是执行“max=num2;”分支,最后都接着执行“printf(“maximum is =y\\n”, max);”语句,输出两个整数中的大数。 其对应的图解如图4.2所示。

?? 非0 num1>num2 0 max=num2 max=num1 ?? 图4.2 案例四if??else??语句执行图解

7.if??else??语句书写时注意,if和else对齐,语句组1和语句组2要向后缩进一定的字符。

二、应用举例

【例4-1】用省略else部分的if语句改写本案例。程序如下:

#include #include main() {

int num1,num2,max; clrscr();

scanf(“%d%d”,&num1,&num2); max=num2;

if(num1>num2) /*比较两个数,大数存入变量max中*/ max=num1;

printf(“maximum is =y\\n”, max); }

上述的改写是先假设num2是较大的数,如果num1大于num2,即表达式“num1>num2”的值为非0,说明num1较大,则把num1赋给变量max,否则说明num2是大数,它已经赋给max了,因此不需要再赋值了。上述if语句对应的图解如图4-3所示。

【例4-2】请编程输入学生成绩,并且根据成绩判断其是否通过考试,如果成绩大于等于60,则输出“passed”,否则输出“failed”。

分析:本例要求先输入一个学生的成绩,然后根据其成绩判断是否通过考试,如成绩大于等于60,则通过显示“passed”,否则输出“failed”。 成绩的输入用scanf函数,并且存入score变量中,然后判断score的值是否大于等于60,用if??else??语句实现判断,并输出相应的提示字符。程序如下:

27

?? 非0 num1>num2 0 max=num1 ?? 图4.3 if?? 语句执行图解

#include #include main() {

float score;

clrscr(); scanf(“%f”,&score);

if(score>=60) /*判断score的值是否大于等于60*/ printf(“passed\\n”); else

printf(“failed\\n”); }

【例4-3】对于用if??else??语句构成的如案例这样的简单应用程序,C语言还定义了一个运算符来实现这样的选择功能。

条件运算符:“? :”是条件运算符,其使用形式为:(表达式1)?(表达式2):(表达式3),其计算顺序是:先计算表达式1的值,如果其值为非0(真),则整个条件表达式取表达式2的值,所以接着计算表达式2;如果表达式1的值为0(假),则取表达式3作为条件表达式的值,因此计算表达式3,此时表达式2不进行计算。如max=(num1>num2)?num1:num2一个表达式即可实现if??else??语句的功能。所以用条件运算符来改写案例程序如下,程序更加简洁。

#include #include main() {

int num1,num2,max; clrscr();

scanf(“%d%d”,&num1,&num2); max=(num1>num2)?num1:num2;

printf(“maximum is =%d\\n”, max); }

注:条件运算符是右结合性。

三、习题

1. 如果将【例4-1】中的“max=num2;”语句改成“max=num1;”,应如何修改程序?

28

2. 将案例改成比较两个实数的大小。

3. 某商品零售价为每千克8.5元,批发价为每千克6.5元,购买数量在10千克以上,按批发价计算。设某顾客购买该商品weight千克,试编写程序计算该顾客应付多少钱?

四、实验五 基本if??else??语句实验

4.1实验目的

1. 掌握if……else……语句的功能; 2. 熟悉关系运算符及关系表达式的运算;

3. 掌握单步运行程序的方法。

4.2 单步运行程序

单步运行程序是一种调试程序的方法,在TC环境中,每按一次F7键,程序执行一行,在程序执行暂停时,可以进行入user screen用户查看已输出的结果,还可以增加观察变量以查看程序运行过程中某些关键变量值的变化,从而来查找程序的错误,通过单步执行程序,还可以观察程序执行的路径。以案例程序为例讲解单步调试程序的方法。

(1) 输入程序,并保存;

(2) 编译程序; (3) 连接;

(4) 添加观察变量 ? ? ? ?

用Alt+B打开Break/watch菜单; 选择add watch 命令;

输入变量num1;

重复上述三步二次,加入变量num2和max;

添加了观察变量后,TC界面的下部就出现了一个watch窗口,所添加的观察变量都在watch窗口。

(5)用F7运行程序,每按一次F7,观察并记录watch窗口中变量的值以及所执行的语句,体会if??else??语句所构成的分支结构程序。

(6)程序运行结束后,打开user screen屏幕,记录输出的结果,并与watch窗口所看到的max的值进行比较。

分别用34,56和78,-10两组数据来运行程序,记录每组数据每步执行的语句和变量值的,理解if??else??语句所构成的分支结构程序,根据表达式值的不同,选择不同的分支。

4.3实验内容及步骤

1.用单运行程序的方法,执行【例4-1】的程序,并记录相应变量的值和所执行的语句。 程序:

编译结果: 修改记录: 输入数据1:34回车56回车

第一次按F7键,num1= ,num2= ,max= ,语句: 第二次按F7键,num1= ,num2= ,max= ,语句: 第三次按F7键,num1= ,num2= ,max= ,语句: ??

输入数据2:78回车-10回车

第一次按F7键,num1= ,num2= ,max= ,语句: 第二次按F7键,num1= ,num2= ,max= ,语句: 第三次按F7键,num1= ,num2= ,max= ,语句: ??

29

2.用单步运行程序的方法,执行【例4-2】的程序,并记录相应变量的值和所执行的语句。 程序:

编译结果: 修改记录: 输入数据1:68回车

第一次按F7键,score= ,语句: 第二次按F7键,score= ,语句: 第三次按F7键,score= ,语句: 输入数据2:57回车

第一次按F7键,score= ,语句:

第二次按F7键,score= ,语句: 第三次按F7键,score= ,语句: ??

3.用同样的方法调试习题1,2,3,并进行记录(自己设计记录格式)。 4.用同样的方法调试例4-3的程序,并做好记录。

4.4思考题:

(1) 两次运行程序,应如何选择数据才能保证if语句的分支分别被执行到?

(2) 是不是每个变量的值都需要进行观察?为什么? (3) 单步运行程序的作用是什么?

30

案例五 100分制成绩与等级制成绩转换

教学目的:

1. 掌握嵌套if……else……语句的一种格式;

2. 掌握switch语句。

在实际应用中经常出现条件递进的情况,如对某个对象先判断它是否满足条件A,如满足,则按要求进行处理;如不满足条件A,再判断是否满足B,如果满足,则按相应要求进行处理??,如此不断重复,直到最后一个条件都不满足时,则进行最后的处理。如将100分制的成绩转换A、B、C、

#include #include main() {

float score;

clrscr(); scanf(“%f”,&score);

if(score>=90) printf(“A”); else if(score>=80) printf(“B”); else if(score>=70) printf(“C”); else if(score>=60)

printf(“D”); else

printf(“E”); }

D、E五级等级制的成绩,90分以为A,80~89分为B,70~79分为C,60~69分为D,60分以下为E。程序如下:

一、案例分析

本案例是利用if??else??语句的嵌套来实现对条件依次进行判断,满足某条件,则进行相应的处理,构成多分支结构程序。但是需要注意的是条件要依次递进,不可以出现其它的次序。

1.if??else??语句的嵌套格式之一

if(条件A)

{语句组1;} else if(条件B) {语句组2;} else if(条件C) {语句组3;} ?? else

{语句组n;}

注:if后的条件可以是任何的表达,包括前面已经涉及到的算术表达式和关系表达式。 2.嵌套if??else??语句的执行过程

(1) 计算条件A的值,如果其值为非0,则执行语句组1,执行完语句组1后,程序转if的

31

下一条语句;

(2) 如果条件A的值为0,则计算条件B,如果为非0,执行语句组2,执行完语句组2后,程序转if的下一条语句; (3) 依次类推,直到所有条件的值都为0,则执行语句组n。 注:一个完整的if语句。

3.嵌套if??else??语句的执行过程图解

?? 非0(真) 条件A 0(假) 语句组1 非0(真) 条件B 0(假) 语句组2 非0(真) 条件B 0(假) 语句组3 ?? ?? 图5.1 嵌套if??else??语句执行图解 4.本案例嵌套if??else??语句执行过程图解(图5.2)

32

?? 非0(真) score>=90 0(假) printf(“A”) 非0(真) score>=80 0(假) printf(“B”) 非0(真) score>=70 0(假) printf(“C”) 非0(真) ?? score>=60 0(假) printf(“D”) printf(“E”) ??

图5.2 本案例嵌套if??else??语句执行图解

5.案例执行过程演示

如果一个学生的成绩是75分,也就是在运行程序时,我们输入75,这时对于用嵌套的if??

else??语句所构成的多分支结构程序的执行如图5.3红色部分(虚体)所示,其对应的语句见斜体部分所示,当执行程序时,执行的语句就是斜体所示的语句。

对于分支结构程序,我们上机调试程序时需要注意选择输入数据,保证每个分支至少执行次,如该例,我们应该选择90分以、80~89分、70~79分、60~69分以及60分以下五个数据,运行程序五次,分别输入这五个数据,以观察程序执行的代码,从而可初步确认程序基本正确。如果要比较完善一些,则需要对每一段数据的端点(即边界值)也进行输入,以观察程序在特殊点是不是也能正确。这里还请大家注意,一般情况下我们的程序只能说到目前为止没有发现错误,不能说一个程序完全正确。

33

?? 非0(真) score>=90 0(假) printf(“A”) 非0(真) score>=80 0(假) printf(“B”) 非0(真) score>=70 0(假) printf(“C”) 非0(真) ?? score>=60 0(假) printf(“D”) printf(“E”) ??

图5.3 输入75时分支选择情况

#include

#include main() {

float score;

clrscr(); scanf(“%f”,&score);

if(score>=90) printf(“A”); else if(score>=80) printf(“B”); else if(score>=70) printf(“C”); else if(score>=60)

printf(“D”); else

printf(“E”); }

二、用switch语句改写案例

switch语句是C语言中专门用来实现多分支结构的语句。使用switch语句实现多分支结构比用嵌套的if??else??要方便灵活。

1. switch语句格式

switch(表达式)

{ case 常量1:语句组1;[break;]

34

case 常量2:语句组2;[break;] case 常量3:语句组3;[break;] ??

case 常量n:语句组n;[break;] [default :语句组n+1;] }

2. switch语句执行过程

1) 计算switch后表达式的值,注意,switch语句要求表达式的值为整型或字符型。C语言中的字符是指以单引号“’”起来的单个字符,如’a’,’A’,’1’等。

2) 根据表达式的值,从上到下依次判断表达式的值是否与case后的某个常量匹配(相同),程序将从最先相匹配case后的语句组入口开始执行程序,直到遇到break语句为止,如果没有break语句,则从入口处一直执行程序至switch语句外层的“}”止。

3) 如果没有一个常量与表达式的值相匹配,则从default后入口开始执行程序,直到遇到break语句或switch语句外层的“}”止。

常量:指在程序的执行过程中其值不变量的量。如整型常量56,-123,实型常量5.67,-0.98,3.2e+6,字符常量’w’,’2’,’M’。

格式中用“[]”括起来的部分是可选部分,根据需要进行选择。

break语句就只有break,没有参数,其作用是结束switch语句的执行,使程序转到switch语句的下一条语句执行。

3. 改写后的程序

#include #include main() {

float score;

clrscr(); scanf(“%f”,&score); switch((int)(score)/10 ) {

case 10:

case 9: printf(“A”);break; case 8: printf(“B”);break; case 7:printf(“C”); break; case 6:printf(“D”);break; default : printf(“E”);

} }

用switch语句改写的关键是switch后表达式的确定及case后常量的确定,本例将score的值取整,然后利用两个整数相除结果仍为整数这一规则,使表达式的值为整数,范围在0~10之间。常量10和9说明score的值在90分以上,所以当score的值在90分以上时,将会从case 10:或case 9 处找到入口,从而输出字符“A”,然后运行break;语句,结束switch语句的执行。当输入其它分数时,根据计算的值找到相应case入口,输出对应符号,然后结束switch语句的执行。

三、应用举例

【例5-1】分别用嵌套if??else??语句和switch语句编程为某运输公司计算运费。路程(s)赿远,每公里的运费赿低。标准如下:

s<500,没有折扣 500<=s<1000,5%折扣

35

1000<=s<1500,10%折扣 1500<=s<2000,15%折扣

s>=2000,20%折扣

假设每公里每吨货物的基本运费为p,货物重量为w,距离为s,折扣率为d,则总运费f的计算公式为:

f=p*w*s*(1-d) 分析:如果用嵌套if??else??语句来实现,可以按题目的标准使条件递进,第一个条件是s<500,第二个条件是s<1000,第三个条件是s<1500,依次递进。然后根据条件,选择折扣d,用f=p*w*s*(1-d)公式计算运费。程序如下:

#include #include main() {

float p,w,s,f,d; clrscr();

scanf(“%f”,&p); 输入基本运费; scanf(“%f”,&w); 输入货物重量; scanf(“%f”,&s); 输入运输距离; if(s<500) d=0;

else if(s<1000) d=0.05; else if(s<1500) d=0.1; else if(s<2000)

d=0.15; else

d=0.2;

f=p*w*s*(1-d);

printf(“weight=%f,distance=%f,fee=%f”,w,s,f); }

#include #include main() {

float p,w,s,f,d; clrscr();

scanf(“%f”,&p); 输入基本运费; scanf(“%f”,&w); 输入货物重量; scanf(“%f”,&s); 输入运输距离; switch((int)(s)/500) { case 0: d=0;break; case 1: d=0.05;break; case 2: d=0.1;break; case 3: d=0.15;break; default : d=0.2; }

f=p*w*s*(1-d);

printf(“weight=%f,distance=%f,fee=%f”,w,s,f); }

如果用switch语句实现,关键是找到运输距离和折扣之间的关系,距离每增加500公里,折扣率增加5%,因此把距离除以500作为switch的表达式,case后的常量是从0开始的整数。程序如上。

本例在运行输入数据时,必须保证输入的都是正数。

四、习题

1. 分别用嵌套if??else??语句和switch语句编程判断某人是否属于肥胖体型。 根据体重与身高,得出体指数t=体重W/(身高h)2 (w单位为kg,h单位为m)标准如下: 当t<18时,为低体重; 当18<=t<25时,为正常体重; 当25<=t<27时,为超重体重; 当t>=27时,为肥胖。

2. 某托儿所收2岁到6岁的孩子,2岁、3岁孩子进小班(Lower class),4岁孩子进中班(Middle class), 5岁、6岁孩子进大班(Higher class)。请编程输入孩子年龄,输出年龄及进入的班号。

3. 输入三个整数a、b、c,请编程按从大到小顺序输出它们。

五、实验 实验六 switch和嵌套if语句

36

5.1 实验目的

1. 掌握嵌套if ……else……语句的使用; 2. 掌握switch语句的使用。

5.2 实验内容及步骤

1.用单步运行程序的方法调试案例程序,准备好多组数据,保证每个分支至少执行一次。 程序:

编译结果: 修改记录: 输入数据1:

第一次按F7键,score= ,语句: 第二次按F7键,score= ,语句: 第三次按F7键,score= ,语句: ?? 输入数据2:

第一次按F7键,score= ,语句:

第二次按F7键,score= ,语句: 第三次按F7键,score= ,语句: ??

2.用单步运行程序的方法调试用switch语句修改后的案例程序,准备好多组数据,保证每个case入口至少进入一次。

程序:

编译结果: 修改记录: 输入数据1:

第一次按F7键,score= ,语句: 第二次按F7键,score= ,语句: 第三次按F7键,score= ,语句: ??

输入数据2:

第一次按F7键,score= ,语句:

第二次按F7键,score= ,语句: 第三次按F7键,score= ,语句: ??

3.用单步运行程序的方法调试【例5-1】的两种程序,准备好多组数据,保证每条语句至少执行一次。自己设计记录格式。

4. 调试习题1、2、3,自己设计记录格式。

5.3 思考题

(1)switch和嵌套的if??else??语句所实现的程序是不是任何情况下都可以相互改写?比较两种实现多分支结构的优缺点。

(2)if??else??还可怎样嵌套?

(3)什么时候需要在switch语句中使用break语句?

37

案例六 求1~100的和

教学目的:

1. 熟悉循环结构程序;

2. 掌握实现循环结构的for(;;)语句。

在日常工作或生活中,我们经常碰到需要重复进行某种操作,如求1+2+3+??+100的和,或者是求1*2*3*??*n=n!,需要重复进行加法乘法操作。我们以求1~100的和为例来看如何编写这种需要重复完成某项操作的程序。程序如下 :

#include #include main() {

int i,sum; clrscr();

sum=0; /*存放和值的变量赋初值0*/ for(i=1;i<=100;i++)

sum=sum+i; /*循环体*/ printf(“%d\\n”,sum); }

一、案例分析

上述程序中出现了一个新的语句for,其作用是实现某些语句按需要的次数重复运行。 1. for语句格式

for([表达式1];[表达式2];[表达式3]) 重复执行的循环体语句组;

2. for语句执行过程

1) 计算表达式1;

2) 计算表达式2;若表达式2的值为非0(真)表示循环的条件成立,则转3)执行循环体;若表达式2 的值为0(假)表示循环条件不满足,则结束循环,转5);

3) 执行循环体语句组;

4) 计算表达式3;然后转2);

5) 结束循环,执行for循环之后的语句。 3. for语句执行过程图解(图6.1)

38

?? 计算表达式1 0(假) 计算表达式2 for之后的语句 循环体 非0(真) 计算表达式3 图6.1 for语句执行图解

4. 案例程序执行演示

本案例中有这样一条语句“i++;”其作用等价于“i=i+1;”。运算符“++”称为自增运算符,与其对应的是“--”自减运算符,自增运算符的作用是使变量的值增加1,自减运算符的作用是使变量的值减1。例设变量a的值为6,执行a++后,a的值为7,设变量b的值为5,执行--b后,b的值为4。

自增与自减的前置和后置效果的区别,自增与自减运算符是用于单个变量的运算符,因此是单目运算符,在表达式中,这两个运算符前置和后置时,对于整个表达式值的影响是不同的。如:设变量a的值为6,变量b的值为5,请计算表达式6+(++b)-(a--)的值及a、b的值。由于++b是前置,在表达式的运算中,要先对变量进行自增运算,即b的值先加1,为7,而a--是后置,先取a的值进行表达式的运算,完了之后再使a的值减1,为4,整个表达式的值为6。平时使用时要注意自增自减运算符的前置与后置的问题,单目运算符的优先级高于双目运算符及三目运算符,双目运算符是指一个运算符的运算对象为两个,三目运算符的运算对象为三个。

根据for语句的执行过程图解,可以把案例的for语句执行也用图来表示,见图6.2。

根据for语句执行过程,i从1起,然后判断i是否小于等于100,第1 次i=1当然满足条件,因此执行“sum=sum+i;”语句,接下来计算i++,即表达式3,然后判断i是否小于等于100,当然这次i=2还满足条件,再次重复刚才的过程,直到i++后,i=100,再次判断i是否小于等于100,还是满足条件的,再次执行“sum=sum+i;”语句后,i++后,i=101时,判断i是否小于等于100,这次不满足条件了,因此退出循环,执行for之后的语句。从而完成了求1~100的和。

对于循环结构的程序,需要注意这样的概念:循环体,循环初始化,循环的条件和循环条件控制。在本例中,循环体就是“sum=sum+i;”语句,是重复执行的部分;循环初始化是“sum=0;”和“表达式1,即i=1”;循环的条件是“表达式2 ,即i<=100”;循环控制是使循环的条件趋向不满足,使循环最终能结束,本例是“表达式3,即i++”。

本例循环体共执行了100次。

39

?? i=1 0(假) i<=100 for之后的语句 sum=sum+i i++ 非0(真) 图6.2 本案例for语句执行图解

5. for语句注意点

1) for后的三个表达式都可省略,但“;”不可省略;

2) 当表达式2省略时,表示无条件循环,即条件永远为真,这时需要注意循环体内要有相应的终止循环的命令;注意下面for语句的执行:

for(j=0;j;j++); for(j=1;j;j++);

二、应用举例

【例6-1】编程求正整数n的阶乘n!。其中n由键盘输入。

分析:在本课一开始,我们就见过了求5!的程序。其实求阶乘和求1~100和的程序差不多,只需要将sum的初值改为1,i<=100改为i<=n,将sum=sum+i中“+”改为“*”。并添加一条输入n值的语句。考虑到阶乘的结果比较大,因此sum的类型定义为float,修改后的程序如下:

【例6-2】编程求1+1/2+1/4+1/6+??+1/50的值。

分析:该例同案例相似,也是求和,求的是1除以偶数的和,因此i值的改变每次是加2,并且其初值为2,到50为止,另外存放和值变量的类型是应该定义为实型。程序如下:

40

【例6-1】程序 #include #include main() {

int i,n;

float sum; clrscr();

scanf(“%d”,&n);

sum=1; /*存放阶乘值的变量赋初值1*/ for(i=1;i<=n;i++)

sum=sum*i; /*循环体*/ printf(“%f\\n”,sum); }

【例6-2】程序 #include #include main() {

int j;

float sum; clrscr();

sum=1; /*存放和值的变量赋初值1,这时需要注意*/ for(j=2;j<=50;j=j+2)

sum=sum+1.0/j; /*循环体*/ printf(“%f\\n”,sum); }

三、习题

1. 编程求1000以奇数的和。 2. 编程求1!+2!+??+n!。 3. 编程打印下述图形。

88888888888 88888888888

88888888888 88888888888

4. 编程打印下图(思考题) *

***

*****

四、实验 实验七 for语句构成的循环结构程序

4.1实验目的

1. 掌握循环结构程序的调试方法; 2. 掌握实现循环结构的for语句。

4.2设置断点调试程序的方法

单步执行程序的方法能有效地、一行一行地执行并检查感兴趣变量的值,但是如果程序很长,是

41

难以逐行进行检查的。对于一个较长的程序,常用的方法是在程序中设置若干个断点,程序执行到断点处暂停,用户可以检查此时有关变量或表达式的值。如果未发现错误,就继续执行程序直到下一个断点处,如此一段一段地检查;若在某断点处发现错误,则修改程序,再次重复执行,直到得到正确的结果。这种方法是把一个程序分割成几个段,逐段检查有无错误,从而缩小范围,然后集中精力检查有问题的段。

断点设置的方法是:将光标移到要设置断点的行上,用快捷键CTRL+F8,或者是使用菜单Break/watch下的子菜单Toggle breakpoint。取消断点和设置断点的方法一样,快捷键和菜单命令也一样。下面仍然通过一个例子来讲解断点的设置和调试程序的方法。

2

【例】求解一元二次方程式ax+bx+c=0的根。

#include “math.h” #include “stdio.h” #include “conio.h” main() {

float a,b,c,disc,p,q,x1,x2;

scanf(“%f,%f,%f”,&a,&b,&c); clrscr();

disc=b*b-4*a*c; p=-b/(2*a);

q=sqrt(disc)/(2*a); x1=p+q; x2=p-q;

printf(“x1=%d,x2=%d\\n”,x1,x2); }

这个源程序没有语法错误,顺利通过编译和连接。运行时输入: 1,2,1↙ 输出结果为: x1=0,x2=0

这个结果显然不对。为了找出问题所在,我们通过分析决定在“p=-b/(2*a);”和“printf(“x1=%d,x2=%d\\n”,x1,x2);”语句行设置断点,结果如图6.3所示,这两行以红色显示。

设置断点之后,当使用Run命令执行程序时,遇到断点暂停,并且断点所在行也未被执行,只执行到断点行的上一行。这时就可通过观察窗口检查相关变量的值,见图6.4所示,变量disc的值为0,

图6.3 断点设置结果

42

根据数学知识可知,在输入“1,2,1” 即b=2,a=1,c=1的情况下,disc的值应该是0,由此可知方程应该有两个相等的实根,至此未发现错误。继续全速执行程序,遇到第二个断点时,暂停,再检

图6.4 执行到第一个断点

查相关变量的值,见图6.5所示,可见x1为-1,x2为-1。通过计算可知,方程的两相等实根就是-1,可见到此程序没有问题,那为什么输出结果为0呢?剩下只有一条语句行了,问题就应重点检查“printf(“x1=%d,x2=%d\\n”,x1,x2);”语句行了。变量x1和x2的值确实是正确的方程根,输出时却是错误的,这时经过仔细分析,发现问题出在输出格式上,x1和x2都是实型,可printf中却用了“%d”的格式输出,所以出现错误。

将printf函数中的“%d”改成“%f”,再次运行程序,输出结果为:

x1=-1.000000,x2=-1.000000

结果完全正确。我们再运行一次(断点行不变),这次输入a、b、c的值改为2,3,5。执行到第一个断点暂停,可以看到变量disc的值为-31,方程应该有两个复根,而本程序只能计算实根,当disc的值为负时,在计算平方根时会出现错误。继续运行程序,当执行到“q=sqrt(disc)/(2*a);”时,屏幕

图6.5执行到第二断点

43

闪了一下(这是程序向用户屏幕输出信息,然后又切换到TC窗口而产生的),当执行到第二个断点时,通过用户屏幕可以看到提示的出错信息:

sqrt:DOMAIN error

这个错误提示表示sqrt函数调用时,要求的参数是大于等于0,而本例sqrt函数的参数是-31,从而引起溢出错误。当然这个错误是由于输入a、b、c的值不恰当造成的,程序本身没有错误,不需要修改程序。

一旦程序调试通过,所设置的断点就可清除。断点的设置是有所选择的,一般选择一些关键变量值的改变处,比如上例中disc变量值的变化,这样便于分析变量前后的变化,从而寻找问题。因此调试程序之前需要做好准备工作,全面熟悉程序,做好静态分析,然后再进行动态调试。动态调试时选择单步运行程序还是断点运行程序,这需要具体情况具体对待,对于较短的程序,可以单步运行,对于有些分支程序,也可以通过单步运行来观察分支的条件是否正确。而较长的程序,或者循环的次数较多时,通常采用断点调试方法,这样减少暂停次数,提高调试效率。当然调试程序是项既专业又有技巧的工作,需要不断进行经验总结,才能熟练掌握。

4.3实验内容及步骤

1.用单步调试程序的方法调试案例程序,将求1~100的和,改为求1~5的和。记录如下信息: 程序:

编译结果: 修改记录:

第一次按F7键,i= ,sum= 语句: 第二次按F7键,i= ,sum= 语句: 第三次按F7键,i= ,sum= 语句: ??

2.用设置断点调试程序的方法调试案例程序,将求1~100的和,改为求1~5的和。记录如下信息: 请将“sum=sum+i;”行设成断点。 编译结果: 修改记录:

第一次执行Run命令,i= ,sum= 语句: 第二次执行Run命令,i= ,sum= 语句: 第三次执行Run命令,i= ,sum= 语句: ??

3.用设置断点调试程序的方法调试【例6-1】,并进行记录。 程序:

编译结果: 修改记录: 输入数据1:

第一次执行Run命令,i= ,sum= ,n= 语句: 第二次执行Run命令,i= ,sum= ,n= 语句: 第三次执行Run命令,i= ,sum= ,n= 语句: ?? 输入数据2:

第一次执行Run命令,i= ,sum= ,n= 语句: 第二次执行Run命令,i= ,sum= ,n= 语句: 第三次执行Run命令,i= ,sum= ,n= 语句: ??

4.用设置断点调试程序的方法调试【例6-2】,自己设计记录内容。 5.选择合适的调试方法调试习题并做好记录。 4.4思考题

1. 请比较单步和断点调试程序方法的优缺点。

44

2. 什么情况下选择断点调试程序的方法。

3. 如何设置断点?一般选择什么位置来设置断点。

案例七 求π=4*(1/1-1/3+1/5-1/7+??)的值

教学目的:

1. 进一步熟悉循环的结构;

2. 掌握用while和do ……while语句实现循环结构。

C语言中设计了for、while和do ??while三种语句来实现循环结构,前面已经知道for语句的格式,这次课我们要学习while和do ??while语句的结构。用while和do ??while语句实现计算π=4*(1/1-1/3+1/5-1/7+??)值的程序如下:

/*do??while实现的循环结构*/ /*while实现的循环结构*/

#include “stdio.h” #include “stdio.h”

#include “conio.h” #include “conio.h”

main() main()

{ {

int j,k; int j,k;

float pi,; float pi,;

clrscr(); clrscr();

k=1;pi=0;j=1; /*循环初始化*/ k=1;pi=0;j=1; /*循环初始化*/

do while(1.0/j>0.0001) /*循环条件*/

{ {

pi=pi+k*1.0/j; /*循环体*/ pi=pi+k*1.0/j; /*循环体*/

k=-k; k=-k;

j=j+2; /*循环控制变量值的改变*/ j=j+2; /*循环控制变量值的改变*/

} while(1.0/j>0.0001); /*循环条件*/ }

pi=pi*4; pi=pi*4;

printf(“π=%f\\n”,pi); printf(“π=%f\\n”,pi);

} }

一、案例分析

1. do??while和while语句的格式 do

{

循环体语句组; }while(条件表达式); 2. 两种语句的执行过程

do??while语句的执行过程

1) 执行do后的循环体语句组;

2) 计算while后面条件表达式的值; 3) 如果条件表达式的值为非0(真),则转1)继续执行循环体语句组;如果条件表达式为0(假),则结束循环的执行,继续执行while下面的语句。

3. 两种语句执行过程图解(图7.1)

45

while(条件表达式);

{

循环体语句组; }

while语句的执行过程

1) 计算while后面条件表达式的值; 2) 如果条件表达式的值为非0(真),则执

行循环体语句组;然后转1)继续重复上面的过程;

3) 如果条件表达式为0(假),则结束循环

的执行,继续执行while下面的语句。

从图解和上述的执行过程描述可知,do??while和while语句的主要区别在于while语句先进行条件表达式的计算,满足条件才执行循环体,如果第一次条件就为0(假),则循环体一次也不执行就结束循环语句执行;而do??while语句则先执行循环体,然后才计算条件表达式的值,并判断条件是否满足,因此不管怎样,循环体至少执行一次。

4.程序分析

“k=1;pi=0;j=1;”行是循环的初始化部分,给变量赋相应的初值,变量k是用来在计算中改符号位的,第一项是符号位是正,所以k赋为1;pi是用来存放和值的,所以其初值赋为0;j是表示某项

?? ?? 执行循环体语句组 0(假) 计算条件表达式的值 ?? 非0(真) 执行循环体语句组 0(假) 计算条件表达式的值 非0(真) ??

图7.1 b)do??while语句执行图解

图7.1 a)while语句执行图解

的分母值,第一项的分母是1,所以赋其初值为1。

“1.0/j>0.0001”为循环的条件,表示当前项的绝对值大于0.0001时,还需要把此项添加到和值中。

“pi=pi+k*1.0/j; k=-k;”两条语句是循环体,分别完成求和及下一项符号的改变。 “j=j+2;”计算下一项的分母。

在此例中,关键的一个问题是循环条件的确定,本例是当前项的绝对值大于0.0001;第二个问题是每项前的符号的确定,本例用一个整型变量k,使其交替的改为1和-1,以实现当前项符号的确定;由于k,j都是整型,相除时,其值将会为0,因此需要用k*1.0/j这种形式将运算对象值的类型转换为实型。

二、三种实现循环语句的比较

1. 初始化部分 for语句可以将初始化部分的语句放入表达式1中,而while和do??while语句的初始化则需要放在while和do??while语句之前;

2. 循环条件 for语句的循环条件由表达式2表示,而while和do??while语句则放在while后;

3. 循环控制部分 通常控制循环的变量值的改变对于for语句是由表达式3来实现,而while和do??while语句则需要放在循环体内;

4. do??while语句实现的循环,其循环体至少执行一次,所以在选择时应加以注意。 5. 三种语句实现的循环一般是可以相互转换的。

一般情况下,已知次数的循环用for来实现。循环结构程序编写时应特别注意循环初始部分、循环体部分、循环的条件以及循环控制部分。

三、应用举例

【例7-1】一张纸的厚度是0.1mm,珠穆郎玛峰的高度为8848.13m,假如纸张有足够大,将纸对折多少次后可以超过珠峰的高度?(分别用三种循环语句编写)

分析:该题主要是计算是每对折一次,其厚度就是前一次的厚度*2;其次是循环的条件,当厚度超过8848.13后,即停止对折,因此这个循环是不知道次数的,但是需要计算对折的次数,因此每循

46

环一次,需要将计次的变量加1。我们定义以下几个变量: int count;用于计算对折的次数,其初值为0;

float thickness;用于计算当前纸的厚度,其初值为0.0001;

程序如下:

/*while实现的程序*/ #include “stdio.h” #include “conio.h” main() {

int count;

float thickness; clrscr();

count=0;thickness=0.0001; /*循环初始化*/ while(thickness<8848.13) /*循环条件*/

{

thickness=thickness*2; /*循环体*/ count++; }

printf(“thickness=%f,count=%d\\n”,thickness,count); }

/*do??while实现的程序*/ #include “stdio.h” #include “conio.h” main() {

int count;

float thickness; clrscr();

count=0;thickness=0.0001; /*循环初始化*/ do

{

thickness=thickness*2; /*循环体*/ count++;

} while(thickness<8848.13); /*循环条件*/

printf(“thickness=%f,count=%d\\n”,thickness,count); }

/*for实现的程序*/ #include “stdio.h” #include “conio.h” main() {

int count;

float thickness; clrscr();

count=0;thickness=0.0001; /*循环初始化*/ for( ;thickness<8848.13; ) /*循环条件*/

{

thickness=thickness*2; /*循环体*/ count++; }

printf(“thickness=%f,count=%d\\n”,thickness,count); }

47

四、习题

1. 求Fibonacci数列前40个数。该数列的生成方法是:F1=1,F2=1,Fn=Fn-1+Fn-2(n>=3),即从第三个数开始,每个数等于前两个数的和。

2. 求数列的前10项的和。2/1+3/2+5/3+8/5+??

3. 给出一个正整数,编程实现:从低位到高位顺序输出每位数字及位数。 提示:要把一个整数的每一位取出来,需要用到一个新的算术运算符“%”,称之为求余运算,即两个整数相除的余数,如3%2=1,9%5=4,1%5=1,其运算优先级同“*、/”运算符。如取35的每一位,用35先取个位,然后k=35/10,将该数缩小10倍,再用k取出十位。当然不管整数是多少位的,始终重复黑斜体部分即可。

五、实验 实验八 while和do??while语句

5.1实验目的

1. 掌握while和do……while语句; 2. 熟悉三种实现循环结构语句的区别。

5.2实验内容及步骤

1.选择合适的程序调试方法调试案例的两种程序,并设计记录格式。 2.将案例程序改为用for语句实现,并调试程序。 3.调试【例7-1】的三种程序,并进行记录。

4.将【例7-1】用for语句实现的程序进行以下修改,并调试。

将原程序中的下列语句改成一条for语句。 count=0;thickness=0.0001; /*循环初始化*/ for( ;thickness<8848.13; ) /*循环条件*/

{

thickness=thickness*2; /*循环体*/ count++; }

for(count=0,thickness=0.0001; thickness<8848.13;thickness=thickness*2, count++); 5. 调试习题的程序,并做好记录。 5.3思考题

1.三种实现循环结构的语句应如何选用?

48

案例八 打印有规律的图形

教学目的:

1. 掌握嵌套循环(多重循环)结构程序的编写;

实际应用中,程序通常是由基本的顺序结构、分支结构和循环结构根据需要组合而成的。如案例六后的习题4,要求打印一个由“*”组成正三角形,编写实现类似这样有规律的图形,通常采用循环嵌套的结构。由“*”组成的正三角形程序如下:

#include “stdio.h” #include “conio.h” main() {

int row,col; clrscr();

for(row=1;row<=3;row++) /*控制输出图形的行数*/ {

for(col=1;col<=3-row;col++) /*控制每行前面输出的空格数*/

printf(“ “);

for(col=1 ;col<=2*row-1;col++); /*控制每行输出的字符数*/ printf(“*”);

printf(“\\n”); /*换行*/ } }

一、案例分析

1.循环的嵌套

若循环语句中循环体内又完整地包含另一个或多个循环语句,称为循环的嵌套。三种实现循环的语句可以相互嵌套使用。常见的嵌套形式如下图8.1所示:

图8.1 常见的嵌套形式

其中每个方框代表一个循环结构,循环嵌套可以是多层,图8.1最右边的是三层,中间和左边的是二层,中间的结构是外循环中包含有两个并列的循环结构。注意循环的嵌套不能出现交叉的情况。案例程序结构是属于中间一种,一个大循环内包含两个并列的小循环。

2.嵌套循环的执行过程

嵌套循环的执行仍然遵守每种实现循环结构语句的执行过程。内部循环是外部循环的循环体,内外是相对的,比如图8.1中右边的嵌套结构,中间一层循环对于最外层循环来说就是内循环,而对于最内层的循环来说就是外循环,外部循环的每次执行过程中都会触发内部循环从初始值开始执行, 直到内部循环执行结束。外部循环执行了多少次,内部循环就完成多少次完整循环。

3.案例程序的执行过程

49

程序从上往下执行到外层的for语句时,变量row=1,满足循环的条件,所以执行其循环体,循环体的第一条语句是内层循环for,变量col=1,满足内循环的条件,执行内循环的循环体“printf(“”);”,输出一个空格,接着执行内循环for语句的表达式3,使col加1,col=2,然后计算内循环for语句的表达式2,仍然满足条件,继续执行其循环体“printf(“”);”,又输出一个空格,再次重复刚才的过程,直到内层循环的条件不满足时,转而执行内层循环for语句的下一条语句,在此就是下一个内循环语句,开始该循环的执行,输出第一行的一个*,当这层循环结束后,要换行准备下一行的输出,因此在第二个内层循环结束之后,一定要有一个换的printf函数调用,即“printf(“\\n”);”。“printf(“\\n”);”语句执行完之后,继续外层循环for语句的表达式3的计算,使row加1,然后执行外层循环for语句的表达式2,仍然满足条件,所以再次执行外层循环的循环体,即内层循环的第一个for语句又从col=1开始执行,重复前面的过程,在第二行输出一个空格和三个*,然后是换行。再次继续外层循环for语句的表达式3的计算,使row加1,然后执行外层循环for语句的表达式2,仍然满足条件,所以再次执行外层循环的循环体,即内层循环的第一个for语句又从col=1开始执行,重复前面的过程,在第三行输出0个空格和五个*,然后是换行。再次继续外层循环for语句的表达式3的计算,使row加1,然后执行外层循环for语句的表达式2,这次不满足条件,所以结束外层循环的执行,继续执行外层循环的下一条语句,在本例中,没有下一条语句,因此结束整个程序的执行。

4.有规则图形打印的方法总结 图形的打印规律是:

1) 数清图形的行数,可以从0开始,也可以从1开始,如本案例是3行,从1数到3; 2) 找出每行符号的个数和行数的关系,如本案例,第一行1个*,第二行3个*,第三行5个*,

*的个数和行的关系是:2*行数-1,注意由于是一个正三角形,我们看到的是*,由于printf函数输出总是从光标当前位置开始,并不在我们希望的位置,因此还需要找出每一行需要输出的前导空格数,本案例前导空格和行数关系是:3-行数。

3) 程序结构 外层循环控制图形输出的行数,内层的第一个循环控制前导空格的输出,第二个

循环控制输出符号的个数,外循环循环体的最后一条语句是调用printf函数实现换行的语句,这一行千万不可少,否则所有的符号只会输出在一行上。 以上规则主要用于下列类似图形。

* *** *****

* *** *****

* *** *****

* * * * *

***** ***** *****

* *** ***** *** *

对于右侧的菱形图形,也是应用上述规则,只是应用时把菱形分成上下两段进行编程。要打印其它的有规律图形,只要灵活运用上述方法即可。

二、应用举例

【例 8-1】请编程打印下列由“8”组成的图形。

分析:根据前述的方法,该图有4行,每行的字符个数和行数相同,每行输出的8 前导空格数与行的关系是4-行数。(行从1 计数) 88 程序如下: 888 8888

50

本文来源:https://www.bwwdw.com/article/atpp.html

Top