第3章算法概念与顺序结构程序设计 一个程序的主要功能是实现对数据的处理,程序设计就是考虑如何描述数据并对数据操作的步骤,即算法。所以算法是程序的灵魂。从程序流程来看,程序可分为三种基本结构,即顺序结构、选择结构和循环结构。通过这三种基本结构的嵌套和组合可以实现各种复杂的程序。 本章主要介绍算法概念及顺序结构程序设计思想。 3.1算 法 简 介 在程序设计中,需要考虑两方面的内容:一方面是对数据的描述,另一方面是对数据操作的描述。其中,对数据的描述是指“对程序中要用到的数据进行类型的定义和存储形式的说明”,即数据结构(Data Structure);对操作的描述是指“操作的具体步骤”,即算法(Algorithm)。在这里,数据是操作的对象,操作的目的是对数据进行加工处理,以得到预期的结果。 3.1.1算法的概念 瑞士著名的计算机科学家、PASCAL语言的发明者沃思(Niklaus Wirth)提出了程序定义的著名公式: 程序=算法+数据结构这个公式说明了算法与程序的关系。 通常认为,算法是在有限步骤内求解某一问题所使用的一组定义明确的规则。通俗地说,就是计算机解题的过程。在这个过程中,无论是形成解题思路还是编写程序,都是在实施某种算法。前者是推理实现的算法,后者是操作实现的算法。 在日常生活中做任何一件事情,都是按照一定规则,一步一步进行,例如在工厂中生产一部机器,先把零件按一道道工序进行加工,然后,又把各种零件按一定规则组装成一部完整机器。在农村中种庄稼有耕地、播种、育苗、施肥、中耕、收割等各个环节。这些步骤都是按一定的顺序进行的,缺一不可,次序错了也不行。编写程序也如此,程序中的一个算法如果有缺陷,执行这个算法就不能解决问题。 计算机解决问题的方法和步骤,称为计算机算法。计算机算法分为两大类: 数值运算算法和非数值运算算法。数值运算的目的就是得到一个数值解,如科学计算中的数值积分、解线性方程等的计算方法,就是数值计算的算法。非数值运算的面非常广,一般多应于事务管理领域、文字处理、图像图形等的排序、分类、查找,就是非数值计算的算法。 算法并不给出问题的精确解,只是说明怎样才能得到解。每一个算法都是由一系列的操作指令组成的。这些操作包括加、减、乘、除、判断等,按顺序、选择、循环等结构组成。所以研究算法的目的就是研究怎样把各种类型的问题的求解过程分解成一些基本的操作。 算法设计好之后,要检查其正确性和完整性,再根据它编写出用某种高级语言表示的程序。程序设计的关键就在于设计出一个好的算法。所以,算法是程序设计的核心。 一个算法还应具备以下5个重要特性。 (1) 有穷性: 一个算法必须保证执行有穷步之后结束,不能无休止地执行下去。 (2) 确定性: 算法的每一个步骤必须具有确切的含义,执行何种动作不能有二义性,目的明确。 (3) 可行性: 算法中的每一步操作都必须是可执行的,也就是说算法中的每一步都能通过手工或机器在有限时间内完成,这称为有效性。不切合实际的算法是不允许的。 (4) 输入: 一个算法中有零个或多个输入。这些输入数据应在算法操作前提供。 (5) 输出: 一个算法中有一个或多个输出。算法的目的是用来解决一个给定的问题,因此,它应该给出计算产生的结果,否则,就没有意义了。 实际上,编写一个完整的程序还需要采用结构化的程序设计方法以及选择适当的语言工具和环境。 3.1.2算法的常用描述方法 从上面的分析可知,算法是解决问题的一系列有序指令。设计一个算法或描述一个算法的最终目的是要通过程序设计语言来实现。如何将算法转化为程序设计语言是程序员要解决的关键问题。 对算法而言,它是对某一问题求解步骤的考虑,是解决问题的一个框架流程,而程序设计则是要根据这一求解的框架流程进行语言细化,实现这一问题求解的具体过程。因此,从算法到程序设计是一个由粗到细的过程。 描述算法有多种不同的方法,采用不同的算法描述方法对算法的质量有很大影响。常用的描述方法有自然语言、流程图、NS图和伪代码等。 1. 自然语言 自然语言就是人们日常使用的语言,如汉语、英语等。就像写文章所列的提纲一样,有序地用简洁的语言加数学符号来描述。用自然语言描述算法的优点是简捷易懂,便于用户之间进行交流;缺点是文字冗长,容易产生歧义。例如有这样一句话: “小王对小李说他要去学校。”请问是小王要去学校呢,还是小李要去学校呢?没有特定的语言环境就很难判断出来。另外,将自然语言描述的算法直接拿到计算机上进行处理,目前还存在一定的困难。因此,除了特别简单问题,一般情况下不使用自然语言来描述算法。 【例3.1】用自然语言描述a=50与b=20的和。 (1) 定义两个整型变量a和b。 (2) 给a赋值为50,给b赋值为20。 (3) 定义一个变量sum并初始化为0。 (4) 计算a+b,并将计算的结果赋给sum。 (5) 输出计算结果sum。 (6) 结束。 2. 流程图 流程图是于20世纪50~60年代兴起的一种算法描述方法,它的特点是用一些图框来表示各种类型的操作,用流线表示这些操作的执行顺序。这种方式直观形象,容易转化成相应的程序语言。目前所采用的是美国国家标准协会(American National Standard Institute,ANSI)规定的一些常用的流程图符号,如图31所示。 图31常见流程图符号 说明: (1) 起止框: 用圆角矩形表示算法的开始和结束;一个算法只能有一个开始处,但可以有多个结束处。 (2) 输入输出框: 用平行四边形表示数据的输入或计算结果的输出。 (3) 判断框: 用菱形表示判断,其中可注明判断的条件。 图32流程图 (4) 处理框: 用矩形表示各种处理功能,框中指定要处理的内容,该框有一个入口和一个出口。 (5) 流程线: 用箭头来表示流程的执行方向。 (6) 连接点: 用于连接因画不下而断开的流程线。 (7) 注释框: 用来对流程图中的某些操作做必要的补充说明,以帮助阅读流程图的程序员更好地理解流程图中某些操作的作用。 【例3.2】用流程图的形式描述出1~100能被3整除的数(见图32)。 3. NS图 虽然流程图可以通过具有特定意义的图形、流程线以及简要的文字说明来表示程序的运行过程,但是在使用过程中,人们却发现由于流程图对流程线的使用没有任何限制,流程可以随意地转向,使得流程图变得毫无规律,给阅读者带来很大困难,也难以修改。为此,1973年美国学者I.Nassi和B.Shneiderman提出了一种新的流程图形式。在这种流程图中,完全去掉了带箭头的流程线。它把整个算法写在一个矩形框内,在该框内还可以包含其他的从属于它的框,整个算法的结构由上而下顺序排列,这种流程图称为NS结构化流程图,简称NS图。NS图适用于结构化程序设计,因此备受欢迎。 NS图用以下的流程图符号。 (1) 顺序结构: 如图33所示,A、B、C三个框组成一个顺序结构。 (2) 选择结构: 如图34所示,当条件成立时执行A操作,不成立则执行B操作。请注意图34是一个整体,代表一个基本结构。 (3) 循环结构: 如图35为当型循环结构,表示当条件P1成立时反复执行A操作,直到条件不成立为止。图36所示为直到型循环结构。图33顺序结构 图34选择结构 图35当型循环结构 图36直到型循环结构 【例3.3】用NS图的形式描述出求1~100的和(见图37)。 图37当型和直到型的NS图 4. 伪代码 伪代码(Pseudocode)也是一种算法描述语言,但不是一种现实存在的编程语言。使用伪代码的目的是为了使被描述的算法更容易地以任何一种编程语言(Pascal、C、Java等)实现。它既综合使用了多种编程语言中的语法和保留字,也使用了自然语言。 因此,伪代码是用介于自然语言和计算机语言之间的文字和符号来描述算法的。使用伪代码表示的算法结构清晰,代码简单,可读性好,在计算机教学中通常使用。 【例3.4】用伪代码描述出50以内能被7整除的所有正整数。i=1 当(i≤50) { if (i % 7=0) 输出i; i=i+1; }注意: 伪代码书写格式比较自由,可以按照人们的想法随手书写,但伪代码也像流程图一样用在程序设计的初期,帮助写出程序流程。简单的程序一般都不用写流程、写思路。但是对于结构复杂的程序,最好还是把流程写下来,总体上考虑整个功能如何实现。写好的流程不仅可以用来与他人进行交流,还可以作为将来测试、维护的基础。 3.2C语句概述 C程序对数据的处理是通过语句的执行来实现的,语句是用来向计算机系统发出操作指令。一条语句经编译后产生若干条机器指令。C语句是C源程序的重要组成部分,是用来完成一定操作任务的。从第1章的简单C程序介绍中已经了解到一个函数包括声明和实现两个部分,其中声明部分的内容不产生机器操作,仅对变量进行定义,因此不能称为语句,如“int a;”不是C语句。而执行部分则是由C语句组成的,如sum=a+b;。 C语句可以分为如下五大类。 1. 表达式语句 由表达式组成的语句称为表达式语句。C语言的任意一个表达式加上分号就构成了一个表达式语句,其语句格式为表达式;功能: 计算表达式的值或改变变量的值。 表达式语句可分为赋值语句和运算符表达式语句两种。 1) 赋值语句 赋值语句是由赋值表达式后跟一个分号组成。例如:x=2;/给x赋值为2/ x=y+z; /计算y+z的和并赋值给变量x/2) 运算符表达式语句 运算符表达式语句是由运算符表达式后跟一个分号组成。例如:i++; /语句的功能是使变量i的值自增1/ a+b;/算术表达式语句,计算a与b的和/ a=3,b=a+2,c=a+1;/由三个赋值语句组成的逗号表达式语句/ 注意: (1) C语言将赋值语句和赋值表达式区分开来,不仅增加了表达式的应用,而且使其具备了其他语言中难以实现的功能。 (2) 分号是C语言语句结束的标志。 2. 控制语句 控制语句是用于控制程序的流程,以实现程序的各种结构。它们由特定的语句定义符组成,C语言有9种控制语句。 (1) if语句(条件语句)。 (2) switch语句(多分支选择语句)。 (3) while语句(循环语句)。 (4) dowhile语句(循环语句)。 (5) for语句(循环语句)。 (6) break语句(中止执行switch或循环语句)。 (7) goto语句(无条件转向语句,此语句尽量少用,因为这不利结构化程序设计,使程序流程无规律、可读性差)。 (8) continue语句(结束本次循环语句)。 (9) return语句(从函数中返回语句)。 3. 函数调用语句 由一次函数调用加一个分号构成,其一般形式为函数名(实际参数表);功能: 执行函数语句就是调用函数体并把实际参数赋予函数定义中的形式参数,然后执行被调函数体中的语句,求出函数值。例如:printf("This is a C program");程序说明: 这条语句用于在屏幕上显示字符串"This is a C program"。 注意: 在C语言中无输入输出语句,其输入输出功能是由C库函数所提供,其中printf为标准输出函数。 4. 空语句 空语句用一个分号表示,其一般形式为;功能: 在程序中空语句常用于空循环体或被转向点。它在语法上占有一个简单语句的位置,实际上执行该语句不执行任何操作。 5. 复合语句 用{}把多个语句括起来组成的一个语句称为复合语句。在程序中应把复合语句看成是单条语句,而不是多条语句。例如:{ x=y+z; a=b+c; printf("%d,%d",x,a); }这是一个整体,应该把它看作一条复合语句。 注意: (1) 复合语句内的各条语句都必须以“;”结尾;此外,在“}”外不能加分号。 (2) 在复合语句内定义的变量是局部变量,仅在复合语句中有效。 最后还需说明: C语言对语句的书写格式无固定要求,允许一行书写多条语句,也允许一条语句分行书写。 3.3C语言的基本输入与输出 C语言本身不提供输入输出语句,其输入输出功能是由C语言的库函数提供。C语言具有很丰富的库函数。本节主要介绍C语言库函数中的字符输入输出库函数、格式化输入输出库函数。它们对应的头文件为stdio.h。 3.3.1字符输入输出函数1. 字符输出函数putcharputchar函数是向标准输出设备输出一个字符, 其一般形式为putchar(ch)其中,ch为一个字符变量或常量。 【例3.5】输出单个字符。#include void main() { char m,n;/定义字符变量/ m='a'; n='b';/给字符变量赋值/ (m>=n)?putchar(m):putchar(n);/输出字符/ }运行情况:b也可以输出控制字符,如用putchar('\\n')来输出一个换行符,使显示器光标移到下一行的行首,即将输出的当前位置移到下一行的开头。例如:putchar('O');putchar('\\n')putchar('K');则运行结果为O K也可以输出其他转义字符,例如:putchar('\\141')/输出字符a/ putchar('\\\\')/输出反斜杠"\\"/2. 字符输入函数getchar getchar函数是从键盘上读入一个字符,其一般形式为getchar()函数的值就是从输入设备得到的字符。 【例3.6】输入字符举例。#include void main() { char ch; ch=getchar();/从键盘读入一个字符/ putchar(ch);/显示输入的字符/ }运行情况:c↙(输入字符c并回车) c(输出的结果)注意: (1) getchar函数只能接受单个字符,该字符可以赋给一个字符变量或整型变量,也可以不赋给任何变量,作为表达式的一个运算对象参加表达式的运算处理。 (2) 如果在一个函数中要调用putchar或getchar函数,则应该在函数的前面(或本文件开头)用包含命令#include。 3.3.2格式输入输出函数1. 格式输出函数printfprintf函数是格式化输出函数, 它的作用是向标准输出设备按规定格式输出信息。它的函数原型在头文件stdio.h中。但作为一个特例,不要求在使用printf函数之前必须包含stdio.h文件。其一般形式为printf("<格式控制>", <输出表列>)功能: 将输出表列的值按指定格式输出到标准输出终端上。例如:printf("%d,%c\\n", i,c);圆括号内包括两部分。 (1) “格式控制”是用双引号括起来的字符串,也称“格式控制字符串”,它包括三种信息。 ① 格式说明,由%和格式字符组成,用来确定输出内容格式,如%d、%c等,它总是由%字符开始的。 ② 普通字符, 这些字符在输出是按原样输出,主要用于输出提示信息。如上面printf函数中双引号内的逗号、空格等。 ③ 转义字符,转义字符指明特定的操作,如\\n表示换行,\\r表示回车。 (2) “输出表列”列出要输出的数据或表达式,它可以是零个或多个,每个输出项之间用逗号分隔,输出的数据可以是任何类型。但需注意输出数据的个数必须与前面格式化字符串说明的输出个数一致,顺序也一一对应,否则将会出现意想不到的错误。 【例3.7】格式输出。#include void main() { int x=97,y=98; printf ("%d %d\\n ",x, y); printf ("%4d, %-4d\\n" ,x, y); printf ("%c, %c\\n" ,x, y); printf ("x=%d, y=%d", x, y); }运行情况:97 98 97, 98 a, b x=97,y=98程序说明: 在本例中四次输出了x和y的值,但由于格式控制串不同,输出的结果也不相同。第四行的输出语句格式控制串中,两个格式串%d之间加了一个空格,它是非格式字符,所以输出的a和b值之间有一个空格。 第五行的输出语句格式控制串中,加入了域宽控制符和对齐控制。如%4d,是以四个域宽输出的,所以前面会有两个空格,包括数字占四个位置。而%-4d,与%4d大致相同,但-4表示左对齐。 第六行的输出语句格式控制是要求按%c格式输出,因此输出的是字符a和b。 第七行的输出语句格式控制为了提示输出结果又增加了非格式字符串“x=”和“y=”,故而输出的结果为x=97和y=98。 2. printf函数中的格式说明 printf函数格式说明的一般形式为%[标志][输出最小宽度][.精度][长度][类型]其中方括号[]中的项为可选项。各项的意义介绍如下。 1) 标志 标志为可选择的标志字符,常用标志字符有-、+、#、空格四种,标志字符及其含义如表31所示。表31标志字符及其含义 标志格式字符标志格式意义-结果左对齐,右边填空格(默认为右对齐输出)+正数输出加号(+),负数输出减号(-)#在八进制和十六进制数前显示前导0、0x空格正数输出空格代替加号(+),负数输出减号(-)2) 输出最小宽度 用十进制正整数来表示输出值的最少字符个数。若实际位数多于定义的宽度,则按实际位数输出, 若实际位数少于定义的宽度则补以空格。例如:printf("%5d\\n",789); printf("%-5d\\n",789); printf("%+5d\\n",789);输出结果为:_ _789 789_ _ _+7893) 精度 精度格式符以小数点“.”开头,后跟十进制整数来表示。其意义: 如果输出整数,则表示至少要输出的数字个数,不足补数字0,多则原样输出;如果输出的是实数,则表示小数点后至多输出的数字个数,不足补数字0,多则做舍入处理;如果输出的是字符串, 则表示输出的字符个数,不足补空格,多则截去超过的部分。例如:printf("%8.4f\\n",1.2312345); printf("%8.7f\\n",1.23123); printf("%7.5s\\n","chinese");/表示输出7位域宽,5位字符/ printf("%7.2s\\n","chinese");/表示输出7位域宽,2位字符/输出结果为_ _1.2312 1.2312300 _ _chine _ _ _ _ _ch4) 长度 长度格式符有h和l两种,h表示按短整型数据输出,l表示按长整型或双精度型数据输出(实际上,数据类型在内存中占据的字节数随编译器的位数决定)。例如:long n=123456; printf("%ld",n);输出结果为123456将第二行printf("%ld",n);改为printf("%hd",n);输出结果为-76165) 类型 类型字符用于表示输出数据的类型,其格式符和意义如表32所示。表32printf格式字符 格 式 字 符格式字符的意义d(或i)以十进制形式输出带符号整数(正数不输出正号)o以八进制形式输出无符号整数(不输出前缀0)x(或X)以十六进制形式输出无符号整数(不输出前缀0x)u以十进制形式输出无符号整数f以小数形式输出单、双精度实数,隐含输出6位小数e(或E)以指数形式输出单、双精度实数,尾数部分小数位数为6位g(或G)以%f或%e中较短的输出宽度输出单、双精度实数续表格 式 字 符格式字符的意义c输出单个字符s输出字符串%输出百分号(%)3. 输入输出的格式控制字符举例说明 现就常见的格式控制字符的使用举例说明如下。 1) d格式符 d格式符的含义是按十进制整型数据格式输出,有%d、%md和%ld三种用法。其中,%d是按整型数据的实际长度输出;%md中的m为指定输出字段的宽度,如果数据的位数小于m,则左端补以空格,若大于m,则按实际位数输出;%ld是输出长整型数据。 例如:long a=65432; printf("%d\\n",100); printf("%4d,%4d\\n",123,12345); printf("%8ld\\n",a);其输出结果为100 _123,12345 _ _ _654322) o格式符 o格式符的含义是以八进制数形式输出整数,即内存单元中的各二进制位的值按八进制形式输出。例如:int n=-1; printf("%d,%o",n,n);在Visual C++ 6.0中的输出结果为-1,37777777777这是由于-1在内存中是以补码的形式存放的。 注意: 八进制形式输出的整数是不考虑符号的,即将符号位也一起作为八进制数的一部分输出,不会输出带负号的八进制整数。对长整型数可以用%lo格式输出,同样也可以指定其字段宽度。 3) x格式符 x格式符的含义是以十六进制数形式输出整数,即内存单元中的各二进制位的值按十六进制形式输出,有小写和大写两种形式。例如:int n=-1; printf("%d,%x,%X",n,n,n);输出结果为-1,ffffffff,FFFFFFFF同样,十六进制形式输出的整数也是不考虑符号的。长整型数也可以用%lx格式输出,也可以指定其字段宽度。 4) u格式符 u格式符的含义是以十进制形式输出unsigned型数据。一个有符号整数可以用%u格式输出;反之,一个unsigned型数据也可以用%d格式输出。在输出时按它们之间相互赋值的规则进行处理。例如:int n=-1; printf("%d,%u",n,n);在Visual C++ 6.0中的输出结果为 -1,42949672955) f格式符 f格式符的含义是按小数形式输出十进制实数(包括单、双精度),有%f、%m.nf和%-m.nf三种形式。其中,%f格式不指定字段宽度,由系统自动指定,使实数的整数部分全部输出,并输出6位小数。应当注意,并非全部数字都是有效数字。单精度实数的有效位数一般为7位,双精度实数的有效位数一般为16位。例如:float x,y; double a,b; x=111111.111; y=222222.222; a=1111111111111.111111111; b=2222222222222.222222222; printf("%f,%f",x+y,a+b);输出结果为333333.328125,3333333333333.333000可以看到: 对于x+y的和只有前7位数字是有效的数字;对于a+b的最后3位小数是无意义的(超过16位)。 %m.nf指定输出的数据共占m列,其中有n位小数。如果m的值大于数值长度,则左端补空格。 %-m.nf和%m.nf基本相同,只是使输出的数值向左端靠齐,右端补空格。例如:float n=101.632; printf("%8.2f,%-8.2f", n,n);输出结果为_ _101.63,101.63_ _6) e格式符 e格式符的含义是以指数形式输出实数,有%e、%m.ne和%-m.ne三种形式。其中,%e是以指数按标准宽度输出十进制实数。标准输出宽度共占13位,分别为: 尾数的整数部分为非零数字占1位,小数点1位,小数占6位,e占1位,指数正(负)号占1位,指数占3位。例如:float n=1230.4567890; printf("%e",n);输出结果为1.230457e+003%m.ne指输出实数至少占m位,n为尾数部分的小数位数。不足则在左端补空格,多出则按实际输出。 %-m.ne和%m.ne基本相同,只是使输出的数值向左端靠齐,右端补空格。例如:float n=123.456; printf("%10.2e,%10e,%-10.2e",n,n,n);输出结果为_1.23e+002,1.234560e+002,1.23e+002_7) g格式符 g格式符的含义是根据数值的大小,自动选f格式或e格式(选择输出时占宽度较小的一种)输出一个实数,且不输出无意义的零。例如:float n=123.456; printf("%f,%e,%g",n,n,n);输出结果为123.456001,1.234560e+002,123.4568) c格式符 c格式符的含义是输出一个字符。由于在内存中字符是以它的ASCII码来存放的,因此,对于一个整数,只要它的值在0~255,就可以用字符形式输出。当然,对于c格式符,也可以指定输出的宽度。例如:int i=97; char c='a'; printf("%d,%c,%c,%d,%3c",i,i,c,c,c);输出结果为97,a,a,97,_ _a9) s格式符 s格式符的含义是输出一个字符串,有%s、%ms、%-ms、%m.ns和%-m.ns五种形式。其中,%s控制输出一个字符串。例如:printf("%s","program");输出结果为program%ms表示当字符串长度大于指定的输出宽度m时,按字符串的实际长度输出;当字符串长度小于指定的输出宽度m时,则在左端补空格。同样,%-ms和%ms基本相同,当字符串长度大于指定的输出宽度m时,按字符串的实际长度输出;而当字符串长度小于指定的输出宽度m时,在右端补空格。例如:printf("%5s,%10s,%-10s","program","program","program");输出结果为program,_ _ _program,program_ _ _%m.ns表示输出占m列,但只取字符串中左端n个字符。这n个字符输出在m列的右侧,左补空格。 同样,%-m.ns和%m.ns中的m和n的含义相同,只是n个字符输出在m列的左侧,右补空格。若n>m,则m自动取n值,即保证n个字符正常输出。例如:printf("%5.3s, %-5.3s,%2.3s","china", "china", "china");输出结果为_ _chi,chi_ _,chi4. 格式输入函数scanf scanf函数是格式化输入函数,是从标准输入设备(键盘)读取输入的信息。 其一般形式为scanf("<格式控制>", <地址表列>)功能: 按规定格式从键盘输入若干任意类型的数据给地址所指的单元,可以是变量的地址,也可以是字符串的首地址。 地址表列表示为&变量(或字符串)。 【例3.8】格式输入。#include void main() { int a,b,c,sum; scanf("%d,%d,%d",&a,&b,&c); if(b>c) sum=a+b; else sum=a+c; printf("%d",sum); }运行情况:3,5,7↙(输入3,5,7并回车) 10(输出的结果)在此,&a、&b和&c中的&是“取地址运算符”,&a表示a在内存中的地址。上面例子中的scanf函数的作用是分别按照变量a、b、c在内存中的地址将a、b和c的值存进去。 注意: 用scanf函数输入数据时,各数据之间要用分隔符,其分隔符可以是一个或多个空格分隔,也可以用回车键或跳格键tab来分隔,也可以如上例那样自定义输入的格式。 5. scanf函数中的格式说明 表33所示列出了在scanf函数可能用到的格式字符。表34列出了scanf函数中的附加格式说明字符。表33scanf 函数可能用到的格式字符 格 式 字 符格式字符意义d(或i)以十进制形式输入带符号整数(正数不输出正号(+))o以八进制形式输入无符号整数x(或X)以十六进制形式输入无符号整数u以十进制形式输入无符号整数f以小数形式输入实数,可以用小数形式或指数形式输入e(或E)与f作用相同g(或G)与f作用相同c输入单个字符s输入字符串,将字符串送到一个字符数组中,在输入时以非空白字符开始,以第一个空白字符结束。字符串以串结束标志“\\0”作为其最后一个字符表34scnanf函数中的附加格式说明字符 字符说明l用于输入长整型数据以及double型数据h用于输入短整型数据M指定输入数据所占宽度,域宽应为正整数*表示本输入项在读入后不赋给相应的变量6. scanf函数的使用要点 (1) 格式符的个数必须与输入项的个数相等,数据类型必须从左至右一一对应。例如:scanf("%d,%c",&a,&c); printf("%d,%c",a,c);输入时用以下形式:5,c↙(输入5,c并回车) 5,c(输出的结果)(2) 用户可以指定输入数据的域宽,系统将自动按此域宽截取所读入的数据。例如:scanf("%3d%3d",&a,&b);运行时若按以下形式输入:123456↙(输入123456并回车)系统自动将123赋值给a,将456赋值给b。 (3) 输入实型数据时,用户不能规定小数点后的位数。例如:scanf("%7.2f",&a);是错误的。 (4) 输入实型数据时,可以不带小数点,即按整型数方式输入。例如:scanf("%f",&a);可以用如下输入方式:123↙(输入123并回车)(5) 从终端输入数值数据时,遇下述情况系统将认为该项数据结束。 ① 遇到空格、回车符或制表符(Tab),故可用它们作为数值数据间的分隔符。 ② 遇到宽度结束,如%4d表示只取输入数据的前4列。 ③ 遇到非法输入,例如,假设a为整型变量,ch为字符型变量,对于scanf("%d%c",&a,&ch); 若有246d↙(输入246d并回车)则系统将认为a=246,ch=d(6) 在使用%c格式符时,输入的数据之间不需要分隔符标志;空格、回车符都将作为有效字符读入。例如:scanf("%c%c%c",&a,&b,&c); 若有b_o_y↙(输入b_o_y并回车)则系统将b的赋值给a,_ 赋值给b,o赋值给了c。 (7) 如果格式控制字符串中除了格式说明之外,还包含其他字符,则输入数据时,这些普通字符要原样输入。例如:scanf("%d_%d" ,&a , &b); 122_23↙(输入122_23并回车) scanf("%d,%d",&a,&b); 122,23↙(输入122,23并回车) scanf("a=%d,b=%d" ,&a, &b); a=123,b=23↙(输入a=123,b=23并回车)(8) 格式说明%*表示跳过对应的输入数据项不予读入。例如:scanf("%2d %2d %2d",&a,&b);若有如下输入:12_345_67↙(输入12 345 67并回车)则表示将12赋给a,67赋给b,而345不赋给任何数据。 (9) 在标准输入中不使用%u格式符,对unsigned型数据以%d、%x、%o格式输入。 3.4顺序结构程序设计3.4.1顺序结构程序设计思想程序基本结构包括顺序结构、选择结构和循环结构,任何一个结构化程序都是由这三种基本结构构成的。顺序结构的设计思想: 首先执行A操作,接着执行B操作,最后执行C操作。它们之间是顺序执行的关系。前面已经介绍过它的NS图(见图33)。 在顺序结构程序中,一般包括两部分内容。 1. 编译预处理命令 在编写程序的过程中,如果要使用C语言标准库函数中的函数,应该使用编译预处理命令,将相应的头文件包含进来。 2. 函数 在函数体中,包括顺序执行的各条语句、函数中用到的变量的说明部分(包括类型的说明)、数据的输入部分、数据运算部分以及数据的输出部分。 3.4.2顺序结构程序设计举例 【例3.9】从键盘输入一个小写字母,要求改用大写字母输出。 程序分析: (1) 定义两个字符变量。 (2) 调用输入函数,输入一个小写字母。 (3) 通过运算将小写字母转化成大写字母(小写-32=大写)。 (4) 调用输出函数,输出大写字母。 据此编写程序如下:#include void main() {char c1,c2; c1=getchar(); c2=c1-32; putchar(c2); }运行情况:a↙(输入字符a并回车) A(输出的结果)【例3.10】输入直角梯形的上底、下底、高,计算该梯形的周长和面积。 程序分析: (1) 定义梯形的上底、下底、高、周长及面积的变量分别为a、b、c、l、s。 (2) 调用输入函数,输入梯形的上底、下底、高。 (3) 通过计算得到梯形的周长和面积。 (4) 调用输出函数,输出梯形的周长和面积。 据此编写程序如下:#include #include void main() { float a,b,c,l,s; float t; scanf("%f,%f,%f",&a,&b,&c); if(a!=b) { if(a0。 (2) 求判别式。 (3) 调用求平方根函数,求方程的根。 (4) 输出。 据此编写程序如下:#include #include void main() {float a,b,c,disc,x1,x2,p,q; scanf("a=%f,b=%f,c=%f",&a,&b,&c); if(a==0){ printf("参数a不能为零\\n"); return; } disc=bb-4ac; if(disc<0){ printf("此一元二次方程无解\\n"); return; } p=-b/(2.0fa); q=(float)sqrt(disc)/(2.0fa); x1=p+q; x2=p-q; printf("xl=%6.2f\\nx2=%6.2f\\n",x1,x2); }运行情况:a=l,b=-3,c=2↙(输入a=l,b=-3,c=2并回车) xl=2.00 x2=1.00(输出的结果)注意: 由于程序中用到数学函数sqrt,因此需用预处理命令中的#include。 3.5编 程 实 践任务: 计算正弦函数的面积【问题描述】 用梯形法计算正弦函数的面积。 【问题分析与算法设计】 把正弦函数分为10个高相等的梯形,计算出10个梯形的面积并相加。 【代码实现】#include #include #define PI 3.14159 int main(){ double a0=(PI/10)sin(PI/10)/2; double a1=(sin(PI/10)+sin(PI/5))(PI/10)/2; double a2=(sin(PI/5)+sin(3PI/10))(PI/10)/2; double a3=(sin(PI3/10)+sin(PI2/5))(PI/10)/2; double a4=(sin(PI2/5)+sin(PI/2))(PI/10)/2; double a5=(sin(PI/2)+sin(PI3/5))(PI/10)/2; double a6=(sin(PI3/5)+sin(PI7/10))(PI/10)/2; double a7=(sin(PI7/10)+sin(PI4/5))(PI/10)/2; double a8=(sin(PI4/5)+sin(PI9/10))(PI/10)/2; double a9=(sin(PI9/10)+sin(PI))(PI/10)/2; double a=a0+a1+a2+a3+a4+a5+a6+a7+a8+a9; printf("正弦函数的面积约为: %10.4f",a); return 0; } 习题1. 选择题(1) 设有如下定义: “int x=10,y=3,z;”,则语句“printf("%d\\n",z=(x%y,x/y));”的输出结果是。 A. 1B. 0C. 4D. 3 (2) 以下合法的C语言赋值语句是。 A. a=b=58 B. k=int(a+b); C. a=58,b=58 D. i=i+1; (3) 若变量已正确说明为int类型,要给a、b、c输入数据,以下正确的输入语句是。 A. read(a,b,c); B. scanf("%d%d%d",a,b,c); C. scanf("%D%D%D",%a,%b,%c); D. scanf("%d %d %d",&a,&b,&c); (4) 若有以下定义:#include void main() {char c1='b',c2='e'; printf("%d,%c\\n",c2-c1,c2-32") ; }则输出结果是。 A. 2,M B. 3,E C. 2,e D. 输出结果不确定 (5) 以下程序段的输出是。#include void main() {float a=68.666;