第章3 按部就班———顺序结构程序设计 3.程序设计的基本步骤及程序执行的流程 1 我们已经了解了一个完整的C语言程序由哪些基本要素组成。当我们需要编写程序 去解决某个问题时,通常要按如下步骤设计程序。 (1)首先针对要求解的问题思考解决思路或建立相应的数学模型。 (2)根据解决思路或数学模型设计出程序的算法,并将其用易于理解的方式表示出来。 (3)用正确的语法将算法变换成对应的程序语句,从而编写出完整的可以正确执行的程序。 (4)根据程序运行结果,验证算法的正确与否,对于不正确的算法要返回第一步进行修 改或重新设计。 要想设计正确的算法,通常会用到“顺序、选择、循环”3种基本的程序控制结构,无论多 复杂的程序,都可由这3种基本流程完成。 (1)顺序结构:各操作按照从上到下的顺序按部就班顺序执行,是一种最简单的基本 结构。如同现实世界中,我们解决许多问题要遵从一定的先后次序是一样的,是一种非常常 见的情形。通过本章的学习,读者将掌握如何设计和编写这种简单结构的程序。 (2)选择结构:又称分支结构,根据是否满足给定的条件从多种操作中选择一种操作。 将在第5章进行详细说明。 (3)循环结构:在一定条件下重复执行某种操作。将在第6章进行详细说明。 3.算法及其表示形式 2 计算机科学把程序设计过程分为两个基本任务:算法设计和算法实现。算法设计是指 用文字或符号描述一组解决某个问题的步骤,而算法实现是指把算法设计的描述翻译成让 计算机能够执行的代码。算法的表示方式不仅可以指导程序设计人员理解算法的基本实现 思路,而且可以促进思考,提高程序的可读性、可靠性,改善程序执行效率,因此算法设计是 计算机编程的关键。 为了便于我们对程序设计算法的理解,我们需要学习算法的表示方法,通常表示算法有 以下几种方式:自然语言表示、流程图表示、伪代码表示。 3.1 用自然语言表示算法 2. 自然语言就是人们日常使用的语言,可以是汉语、英语或其他语言。虽然用自然语言表 32 示算法通俗易懂,但自然语言表示的含义往往不太严格,文字也比较冗长,容易出现歧义。 例如,某天你要出门,你妈妈对你说:“能穿多少穿多少。这(”) 句话的意思是要多穿还是少穿, 要根据当时的天气情况才能判断。因此,除了一些比较简单的问题外,一般不用自然语言表 示算法。 C 3.2 用流程图表示算法 2. 流程图是用一些特定的符号来表示程序的各种操作及执行流程。用流程图表示算法直 观形象,易于理解,是我们常用的算法表示方法,也是本书主要的算法表示方法,需要读者熟 练掌握。 1.传统流程图 美国国家标准学会(AmericanNationalStandardsInstitute,ANSI)规定了一些常用的 符号标准,如图3-1所示,且已为世界各国程序设计人员普遍采用。 语言程序设计面向实践能力培养 图3- 1 传统流程图常用符号 1966年,Bohra和Jacopini运用这些基本符号,针对前述3种基本的程序控制结构,提 出了3种良好的算法表示单元。 (1)顺序结构。如图3-2所示,虚线框内是一个顺序结构,其中A、B两个操作指令按照 箭头方向顺序执行。 (2)选择结构。如图3-3所示,虚线框内是一个选择结构。此结构必须包含一个判断 框(菱形),根据给定的P条件是否成立而选择是执行A指令还是执行B指令。 图3- 2 顺序结构图3- 3 选择结构 (3)循环结构。反复执行某一部分操作,主要分为以下两类。 .while循环结构。如图3-4(a)所示,当给定的条件P成立(值为真),执行A指令,执 行完A后,返回并再次判断条件P是否成立,如果仍然成立,则再次执行A指令,如 此反复判断P条件并执行A指令,直到某次P条件不成立(值为假),此时不再执行 A指令,退出循环结构,继续执行后续语句。 e循环结构。如图3 第 do-whil 先执行A指令,再判断给定的条件P是否成 . 4(b)所示, 立,如果条件P成立(值为真),返回再次执行A指令, P条件,直到某次P条件不成立( 如此反复执行A指令并判断 章按部就班顺序结构程序设计 值为假),此时不再返回执行A指令, 退出循环结 构,继续执行后续语句。 图3- 4 循环结构 2.N-S流程图 传统流程图由于流程线的存在,比较占空间,不太适合较为复杂的算法表示,1973年, 美国学者I.Nasi和B.Shneiderman提出了一种新的流程图形式,去掉了带箭头的流程线, 大大节约了绘图空间,很好满足了复杂算法的表示需求。该流程图由提出者的名字首字母 命名,称为N-S流程图。 (1)顺序结构。如图3-5(a)所示,A、B两个操作指令按照从上到下顺序执行。 (2)选择结构。如图3-5(b)所示,按照从上到下顺序,先判断条件P的值,根据给定的 P条件是否成立而选择执行A指令或B指令。 (3)循环结构。while循环结构如图3-5(c)所示,先判断条件P是否成立,如果成立执 行循环体中的A指令,而后反复判断条件P,成立执行A,直到条件P不成立,退出循环。 do-while循环结构如图3-5(d)所示,先执行循环体中的A指令,再判断条件P是否成立,如 果成立返回去再次执行A指令,如此循环往复,直到条件P不成立退出循环。 图3- 5 N-S流程图 3.3 用伪代码表示算法 2. 伪代码是用介于自然语言和计算机语言之间的文字和符号来描述算法。它如同一篇文 章一样,自上而下地写下来。每一行(或几行)表示一个基本操作。它不用图形符号,不需遵 循固定的、严格的语法规则,可用英文也可中英文混用,但一般要写成清晰易懂的格式,因此 其书写方便、格式紧凑、修改方便、容易看懂,便于向符合语法规则的计算机语言算法(程序) 34 C语 言 程 序 设 计 面 向 实 践 能 力 培 养 过渡。由于具有这些特点,其一般用来设计复杂程度不高的程序算法。 【例3.1】 求自然数1~10之和,用伪代码表示其算法。 begin (算法开始) 0=>sum 1=>i 当i<=10 { sum+i=>sum i+1=>i } 输出sum end (算法结束) 3.3 实际问题引例 问题1:已知,某银行一年期的利率为1.5%,二年期的利率为2.1%。某人去银行存钱, 一年期存款5000元,二年期存款10000元。到期后他共获得多少存款和利息? 解题思路:求解该问题的关键是,先求出一年期存款所获得的利息,再求出二年期存款 所获得的利息,最后将这两项利息相加,再加上存款数目就得到总的存款收益。 问题2:某人去银行兑换外币,人民币对美元的汇率为1人民币兑换0.1512美元,若要 兑换的人民币的金额为10000元,则可兑换多少美元? 解题思路:该问题的求解实际上是一个一元一次方程的求解,只需将人民币的总金额 乘以0.1512,即可求出10000人民币所对应的美元总数。 问题3:已知直角三角形的两条直角边分别为3和4,求三角形的周长和面积。 解题思路:欲求三角形的周长,必须首先求出三角形第三条边的长度,可利用勾股定理 求出,再分别计算三角形的周长和面积,这是一个按照顺序逐步求解的解题过程。 问题4:输入三角形的三边长,使用海伦公式计算三角形的面积(假设三边长符合组成 三角形的边长条件)。 解题思路:假设在平面内,有一个三角形,知边长分别为a、b、c,则三角形的面积S 可 由以下公式求得: S= p(p-a)(p-b)(p-c) 而公式中的p 为半周长: p=(a+b+c)/2 据此,我们可以用N-S流程图表示算法,如图3-6所示。 图3-6 算法流程 可以看到,该问题算法主要由4个步骤组成,按照 从上至下的顺序,就可得到三角形的面积,这是一个简 单的顺序结构算法。 上述几个问题都是现实生活中经常遇到的,每个问 题的求解我们都将按照一定的顺序进行,先完成一个步 骤,再完成下一步骤。这就是本章要介绍的顺序结构程 序设计。 35 第第3 33章 章 按 部 就 班 顺 序 结 构 程 序 设 计 编写程序:有了解题思路,我们就可以将算法用N-S流程图等方法表示出来,编写求解 问题的程序。前面章节我们已经了解到C程序的基本框架为 #include<stdio.h> int main() { ... return 0; } 我们要做的就是将程序中省略号的部分,用合乎C语言语法的语句进行替换,实现算 法,要做到这件事,我们需要先掌握C语言的基本语法知识。 3.4 C语句 3.4.1 分类 通过前面章节的学习,我们已经了解到C程序是由函数中的一条一条语句组成的,从 表现形式和功能来看,通常C语句分为5类。 1.控制语句 控制语句完成程序流程的控制功能,有以下9种。 (1)if()-else:条件语句。 (2)for():循环语句。 (3)while():循环语句。 (4)do-while():循环语句。 (5)continue:结束本次循环语句。 (6)break:中止语句。 (7)switch:多分支。 (8)return:返回语句。 (9)goto:转向语句。 上面语句表示形式中的“()”表示里面有判别条件,“-”表示内嵌有语句,例如: if (a>b) max=a; else max=b; 这里“a>b”就是判别条件,而“max=a;”和“max=b;”为内嵌语句。即比较变量a与b 值的大小,将较大的值存放到变量max中。 2.函数调用语句 函数调用语句由一个函数调用加一个分号构成。例如: printf("Welcome to the world of C."); 3.表达式语句 表达式语句由一个表达式加一个分号构成。例如: a=b+5; 其中“a=b+5”为表达式,加一个分号为语句。 36 C语 言 程 序 设 计 面 向 实 践 能 力 培 养 4.空语句 空语句是只有一个分号的语句。例如: ; 空语句无实际操作,一般用来作为循环语句中的循环体(表示循环什么也不做)。 5.复合语句 复合语句是用一对{}括起来的语句。例如: { z=x+y; t=z/100; printf("%f",t); } 复合语句常用在if语句或循环中,将一条或多条内嵌语句用大括号括起来组成复合语 句,除了能保证程序的执行流程正确,也能使程序更清晰,可读性更强。 注意:复合语句中最后一条语句后的分号不能忽略不写,且大括号后不能加分号。 由以上5类语句,我们可以看到C语句的标志是每条语句结尾有一个分号,没有分号 就不能称其为语句。 3.4.2 赋值语句 在C程序中,最常使用赋值语句和输入/输出语句。我们通常会把程序中的值赋给某 些变量,用于进行下一步运算或者作为结果输出。本节我们先介绍赋值语句,3.5节再来学 习程序的输入/输出。 1.赋值运算符 一个表达式中的“=”就是赋值运算符,和数学里表示式子两边相等不同,它的作用是将 “=”右边的数据赋给“=”左边的某个变量,例如: a = 3+6 这条赋值表达式的作用是将“=”右边的计算结果9,赋值给左边的变量a。 注意:赋值运算符左侧的标识符称为“左值”,出现在赋值运算符右侧的表达式称为“右 值”。右值可以是一个数值,也可以是能计算出结果的表达式,而左值只能是一个变量而不 能是表达式或常量。 2.复合赋值运算符 在赋值符“=”之前加上其他双目运算符,可以构成复合运算符。+=、-+、*=、 /=、%=都是较为常见的复合赋值运算符,例如下面的复合赋值表达式: a + = 8; 等价于 a = a+8; a %= b; 等价于 a = a%b; x *= y+8; 37 第第3 33章 章 按 部 就 班 顺 序 结 构 程 序 设 计 等价于 x = x*(y+8); 注意:右值如果是表达式,要看作一个整体加括号,保证运算的优先级。 C语言采用这种复合运算符,一是为了简化程序,使程序精练,二是为了提高编译效率, 能产生质量较高的目标代码。 3.赋值运算的结合性 赋值运算符与复合赋值运算都是按照“自右而左”的结合顺序,例如: a=b=8; 等价于 a=(b=8); 即先执行“b=8”,再执行“a=b”的运算。 a+=a-=a*a; 等价于 a+=(a-=a*a); 即先进行“a-=a*a”的运算,再将运算结果作为“a+=”的右值,计算出结果。 4.赋值表达式的特殊用法 赋值表达式作为表达式的一种,不仅可以出现在赋值语句中,而且可以以表达式形式出 现在其他语句(如输出语句、循环语句等)中。例如: printf("%d",a=b+8); 将“b+8”的结果存放到变量a中,并输出a的值。 5.赋值过程中的类型转换 如果赋值运算符两侧的类型一致,则直接进行赋值。 如果赋值运算符两侧的类型不一致,但都是数值型或字符型时,在赋值时要进行类型转 换。类型转换是系统自动进行的。转换规则如下。 (1)将浮点型数据(包括单、双精度)赋给整型变量时,先对浮点数取整,然后赋予整型 变量。例如: int i; i = 7.8; 这时i的值为7,由于i是整型变量,对右值做了截断处理。 (2)将整型数据赋给单、双精度变量时,数值不变,但以浮点数形式存储到变量中。 (3)将一个双精度型数据赋给单精度变量时,截取其前面7位有效数字,存放到单精度 变量的存储单元(4字节)中。但应注意数值范围不能溢出;将一个单精度型数据赋给双精 度变量时,数值不变,有效位数扩展到16位,在内存中以8字节存储。 (4)字符型数据赋给整型变量时,将字符的ASCII码赋给整型变量。例如: int i; i = 'a'; 这时i的值为97,即a' '字符的ASCII码。 (5)将一个占多字节的整型数据赋给一个占字节少的整型变量或字符变量时,只将其 38 C语 言 程 序 设 计 面 向 实 践 能 力 培 养 图3-7 低位字节赋值 低字节原封不动地送到该变量,如图3-7所示。 例如: int i=293; //i=293 char c='A'; c=i; //c=37 注意:要避免进行这种赋值,因为赋值后数值可能失真。如果一定要进行这种赋值,应 当保证赋值后数值不会发生变化。 (6)将有符号整数赋值给长度相同的无符号整型变量时,按字节原样赋值。 (7)将无符号整数赋值给长度相同的有符号整型变量时,应注意不要超出有符号整型 变量的数值范围,否则会出错。 6.赋值语句 赋值语句是由赋值表达式加上一个分号构成。赋值语句具有计算和赋值双重功能。程 序中的计算功能主要是由赋值语句来完成。 当我们掌握了赋值语句的用法,我们就可以对变量进行初始化,并进行相应的运算了。 现在让我们补充3.3节的问题4中缺少的语句。 #include<stdio.h> #include<math.h> //包含数学函数库,因为要调用sqrt 函数 int main() { float a=3.4,b=4.5,c=5.6; //a、b、c 为三边长 float p,S; //p 为半周长,S 为面积 p=1.0/2*(a+b+c); S=sqrt(p*(p-a)*(p-b)*(p-c)); //调用开算术平方根函数 … return 0; } 可以看到,算法的前三步我们已经完成,接下来读者需要学习C 语言的输入/输出语 句,从而完成最后一步,输出三角形的面积。 3.5 数据的输入/输出 3.5.1 数据输入/输出的概念 输入/输出是以计算机主机为主体而言的,所谓输出是指从计算机向外部(标准)输出设 备(显示器、打印机)输出数据,反之,输入是指从(标准)输入设备(键盘、鼠标、扫描仪)向计 算机输入数据。C语言本身不提供输入/输出语句,输入/输出操作是由C函数库中的函数 来实现的。 在使用系统库函数时,要用预编译命令#include将有关的“头文件”包括到用户源文件 中(通常写在程序开头)。例如: #include<stdio.h> 或 #include "stdio.h" 39 第第3 33章 章 按 部 就 班 顺 序 结 构 程 序 设 计 其中#include<stdio.h>先从系统目录开始查找要包含的头文件,若找不到,再到用户项目 目录查找,适用于要包含系统提供的头文件情况,以提升查找效率。而#include“stdio.h” 先从项目目录开始查找,若找不到,用户可制定路径查找,常用于包含用户自定义头文件的 情况。 知识点小贴士:stdio.h头文件 stdio是standardinput&output的意思,即标准输入/输出头文件,包含该头文件 通常是为在程序中做输入/输出操作时调用相应的库函数做引用声明。 3.5.2 字符数据的输入/输出 常用的字符输入/输出函数如下。 . 字符输入函数:getchar。 . 字符输出函数:putchar。 . 格式输入函数:scanf。 . 格式输出函数:printf。 . 字符串输入函数:gets。 . 字符串输出函数:puts。 3.5.2.1 用putchar函数输出一个字符 格式: putchar(c) 参数:c为字符常量、变量或表达式。 功能:把字符c输出到显示器。 返值:正常,为显示的字符ASCII码;出错,返回-1(EOF)。 【例3.2】 用putchar函数输出字符。 1 #include<stdio.h> 2 void main() 3 { 4 char a='C', b='A', c='R'; 5 putchar(a); //输出变量a 的值 6 putchar(b); 7 putchar(c); 8 putchar('\n'); 9 } 程序运行结果: CAR 还可用putchar函数输出转义字符,例如: putchar('\102'); 程序运行结果: B 此处的102为八进制数,等于十进制的66,因而输出字符B。 40 C语 言 程 序 设 计 面 向 实 践 能 力 培 养 3.5.2.2 用getchar函数输入一个字符 格式: getchar() 功能:从键盘读一字符。 返值:正常,返回读取的代码值;出错,返回-1(EOF)。 注意:无参数。 【例3.3】 用getchar函数输入字符。 1 #include<stdio.h> 2 void main() 3 { 4 char c; 5 c=getchar(); //输入的字符存入变量c 中 6 putchar(c); 7 putchar('\n'); 8 } 程序运行情况: B ↙ B 从键盘输入字符B按Enter键,屏幕上将显示输出的字符B。 【例3.4】 getchar、putchar函数的使用。 1 #include<stdio.h> 2 void main() 3 { 4 char a, b, c; 5 a=getchar(); //输入的字符存入变量a 中 6 b=getchar(); 7 c=getchar(); 8 putchar(a); //输出变量a 的值 9 putchar(b); 10 putchar(c); 11 putchar('\n'); 12 } 程序运行情况: CAR ↙ CAR 可以看到连续输入CAR并按Enter键后,CAR三个字符分别通过getchar函数存入了 三个变量中,又通过putchar函数将变量的值输出。 如果不连续输入字符,而在输入一个字符后马上按Enter键,会得到如下运行情况: C ↙ A ↙ CA 请读者自行思考是什么原因? (提示:输入的回车符为有效字符)。 3.5.2.3 用printf函数输出数据 printf函数(格式输出函数)的作用是向终端(或系统隐含指定的输出设备,通常是显示 41 第第3 33章 章 按 部 就 班 顺 序 结 构 程 序 设 计 器)输出若干个任意类型的数据,并可灵活指定数据输出格式。 知识点小贴士:printf函数 printf函数又称为标准输出函数,它在stdio.h库函数中定义,只能在控制台程序中 使用。 1.printf函数的一般格式 printf函数的一般格式为 printf(格式控制,输出表列) 例如: printf("%d, %c, %f\n", i, c, f); printf函数的参数包括两部分: (1)“格式控制”是用双引号括起来的字符串,也称转换控制字符串,包括以下两种 信息。. 格式说明。格式说明由“%”和格式字符组成,如%d、%f等。它的作用是将输出的 数据转换为指定的格式输出。格式说明总是由“%”字符开始的。 . 普通字符。普通字符即需要原样输出的字符。如上面printf函数中双引号内的空 格、逗号和换行符。 (2)“输出表列”是需要输出的一些数据,可以是常量、变量或表达式,通常与格式控制 中的控制符按顺序一一对应。 【例3.5】 printf函数的格式说明与输出表列。 int a=3;b=4; printf("a=%d b=%d",a,b); 格式说明输出表列 程序运行结果: a=3 b=4 注意:此处的“a=”、空格、“b=”就是原样输出的普通字符。而前后两个“%d”为格式 说明符,控制输出表列中整型变量a和b的数据输出格式。 2.基本的格式说明符 基本的格式说明符有以下几种。 (1)%d或%i格式符。按十进制整型数据的实际长度输出。 (2)%c格式符。用来输出一个字符。 【例3.6】 字符数据的输出。 1 #include<stdio.h> 2 void main() 3 { 4 char c='a'; 5 int i=97; 6 printf("%c,%d\n",c,c); 7 printf("%c,%d\n",i,i); 8 } 42 C语 言 程 序 设 计 面 向 实 践 能 力 培 养 运行结果: a, 97 a, 97 无论整型变量还是字符型变量,都可以用%d和%c格式符得到相应的运行结果,但要 注意,超出ASCII码范围,整型变量就无法输出对应的正确字符了。 (3)%s格式符。用来输出一个字符串。 例如: printf("%s", "CHINA"); 输出字符串"CHINA"(不包括双引号)。 (4)%f格式符。用来输出实数,以小数形式输出,如不指定整个字段的长度,由系统自 动指定。一般的处理方法:整数部分全部输出,并输出6位小数。 【例3.7】 输出实数时的有效位数。 1 #include<stdio.h> 2 void main() 3 { 4 float x,y; 5 x=111111.111;y=222222.222; 6 printf("%f\n",x+y); 7 } 程序运行结果: 333333.328125 结果中只有前7位是有效数字。由于x和y是单精度变量,所以"x+y"也只能保证7 位的精度,后面几位没有意义。 (5)%e格式符。用格式说明%e指定以指数形式输出实数。 例如: printf("%e",123.456); 输出如下: 1.234560 e+002 C编译系统自动指定给出数字部分的小数位数为6位,指数部分为5位。 printf函数支持的基本格式控制符如表3-1所示。 表3-1 printf函数支持的基本格式控制符 格式字符说 明举 例结 果 d,i 十进制整数inta=567;printf("%d",a); 567 u 无符号的十进制整数inta=567;printf("%u",a); 567 o 八进制无符号整数inta=65;printf("%o",a); 101 x,X 十六进制无符号整数(大小写作用相同) inta=255;printf("%x",a); ff c 单个字符chara=65;printf("%c",a); A s 字符串printf("%s","ABC"); ABC f 小数形式输出浮点数floata=567.89;printf("%f",a); 567.890000 续表 43 第第3 33章 章 按 部 就 班 顺 序 结 构 程 序 设 计 格式字符说 明举 例结 果 e,E 指数形式输出浮点数floata=567.89;printf("%e",a); 5.678900e+02 g,G 以e和f中较短的一种进行输出,且不输 出无意义的零floata=567.89;printf("%g",a); 567.89 %% 百分号本身printf("%%"); % 说明: (1)除了x、e、g格式字符可以大写外,其余格式控制符要用小写。 (2)格式字符与输出项个数应相同,按先后顺序一一对应。 (3)可以在printf函数中的“格式控制”字符串中包含转义字符。 (4)一个格式说明必须以“%”开头,以9个格式字符之一为结束。 (5)格式字符与输出项类型不一致,自动按指定格式输出。 另外,在“%”与格式控制符之间可以插入附加格式字符,即表示为 % 附加格式字符 格式字符 以实现对输出格式更为灵活的控制。 printf函数支持的附加格式控制符如表3-2所示。 表3-2 printf函数支持的附加格式控制符 修 饰 符功 能 m 输出数据域宽,数据长度<m,左补空格,否则按实际输出 .n 对实数,指定小数点后位数(四舍五入) 对字符串,指定实际输出位数 - 输出数据在域内左对齐(默认右对齐) + 在有符号数的正数前显示正号(+) 0 输出数值时指定左面不使用的空位自动用0填充 # 在八进制和十六进制数前显示0,0x前导符 l 在d、o、x、u前,指定输出精度为long型 在e、f、g前,指定输出精度为double型 【例3.8】 附加格式控制符的使用。 int a=1234; float f=123.456; printf("%08d\n",a); //输出00001234 printf("%010.2f\n",f); //输出0000123.46 printf("%0+8d\n",a); //输出000+1234 printf("%0+10.2f\n",f); //输出000+123.46 3.5.2.4 用scanf函数输出数据 scanf函数(格式输入函数)的作用是按照变量在内存的地址将变量值存进去。 44 C语 言 程 序 设 计 面 向 实 践 能 力 培 养 知识点小贴士:scanf函数 scanf函数又称为标准输入函数,其只能在控制台程序中使用,在stdio.h库函数中 定义。 scanf函数一般格式为 scanf(格式控制,地址表列) 例如: scanf("%d%c", &i,&c); 其中“%d%c”为格式控制部分,支持的格式控制符与printf函数一样。输入数据时,在两个 数据之间以一个或多个空格间隔,也可以Enter键、Tab键作为间隔。 地址表列是由若干地址组成的表列,可以是变量的地址,或字符串的首地址,如语句中 的“&i,&c”。“&”是地址运算符,用于自动获取变量在内存中的地址。 scanf函数支持的基本格式控制符如表3-3所示。 表3-3 scanf函数支持的格式控制符 格式字符说 明 d,i 用来输入有符号的十进制整数 u 用来输入无符号的十进制整数 o 用来输入无符号的八进制整数 x,X 用来输入无符号的十六进制整数(大小写作用相同) c 用来输入单个字符 s 用来输入字符串,将字符串送到一个字符数组中,在输入时以非空白字符开始,以第一个空白 字符结束。字符串以串结束标志\' 0'作为其最后一个字符 f 用来输入实数,可以用小数形式或指数形式输入 e,E,g,G 与f作用相同,e与f、g可以互相替换(大小写作用相同) scanf函数支持的附加格式控制符如表3-4所示。 表3-4 scanf函数支持的附加格式控制符 修饰符功 能 l 用于输入长整型数据(可用%ld、%lo、%lx、%lu)以及double型数据(用%lf或%le) h 用于输入短整型数据(可用%hd、%ho、%hx) 域宽指定输入数据所占宽度(列数),域宽应为正整数 * 表示本输入项在读入后不赋给相应的变量 【例3.9】 scanf函数附加格式控制符的使用。 scanf("%4d%2d%2d",&yy,&mm,&dd); 输出如下: 输入 19991015 ↙ 由于指定了域宽,则连续输入的数据会自动根据域宽分割,1999存入变量yy中,10存 45 第第3 33章 章 按 部 就 班 顺 序 结 构 程 序 设 计 入变量mm 中,15存入变量dd中。 前面已经介绍,输入多个数据时,默认用空格、Enter键、Tab键做输入数据的分隔符, 除此之外,还可自定义分隔符。 【例3.10】 scanf函数指定输入分隔符。 scanf("%d,%d",&a,&b); 输出如下: 输入 3,4 ↙ 此处输入语句用了逗号作为指定分隔符,输入数据时必须用逗号做分隔符,才能将3存 入变量a,4存入变量b。如果再用空格等默认分隔符输入数据,将会得不到正确的数据。 以此类推,读者可以自行指定其他的数据输入格式。 注意: (1)用“%c”格式符时,空格和转义字符会作为有效字符输入。例如: scanf("%c%c%c",&c1,&c2,&c3); 输出如下: 输入 a b c ↙ 则字符a' '存入变量c1,两个空格字符存入变量c2,字符b' '存入变量c3。 (2)输入数据时,遇到以下情况认为该数据结束。 . 遇到空格、Tab键或Enter键。 . 遇到宽度结束。 . 遇到非法输入。 例如: scanf("%d%c%f",&a,&b,&c); 输出如下: 输入 1234a123o.26 ↙ 则1234存入变量a,字符a' '存入变量b,123存入变量c。 至此,读者已学习了基本的输入/输出方法,可以将3.3节的问题4补充完整: 1 #include<stdio.h> 2 #include<math.h> //包含数学函数库,因为要调用sqrt 函数 3 int main() 4 { 5 float a=3.4,b=4.5,c=5.6; //a、b、c 为三边长 6 float p,S; //p 为半周长,S 为面积 7 p=1.0/2*(a+b+c); 8 s=sqrt(p*(p-a)*(p-b)*(p-c)); //调用开算术平方根函数 9 printf("a=%7.2f,\nb=%7.2f,\nc=%7.2f\n",a,b,c); 10 printf("s=%7.2f\n",s); 11 return 0; 12 } 输出如下: 输入3.4,4.5,5.6 ↙ a= 3.40, 46 C语 言 程 序 设 计 面 向 实 践 能 力 培 养 b= 4.50, c= 5.60 s= 7.65 3.6 顺序结构程序设计举例 1.求存款利息 已知,某银行一年期的利率为1.5%,二年期的利率为2.1%。某人去银行存钱,一年期 存款5000元,二年期存款10000元。到期后他共获得多少存款利息? (3.3节的问题1) 【问题分析】 欲求该人能够获得的存款利息,需要先求出一年期存款所获得的利息,再求二年期存款 所获得的利息,最后将一年期所获利息与二年期所获利息相加即可得到总的存款利息。 【问题求解】 综合案例1:求存款利息 #include<stdio.h> int main() { float a, b, sum; a = 5000 * 0.015; b = 10000 * 0.021; sum = a + b; printf("%f", sum); return 0; } 程序运行结果: 285.000000 【应用扩展】 由此,我们可以扩展计算企业利润、个人所得税、股票收益率等。 2.兑换外币 某人去银行兑换外币,人民币对美元的汇率为1人民币兑换0.1512美元。若要兑换的 人民币金额为10000元,则可兑换多少美元? (3.3节的问题2) 【问题分析】 求解该问题只需将已有人民币的总金额乘以0.1512即可。 【问题求解】 综合案例2:外币兑换 #include<stdio.h> int main() { float d; d = 10000 * 0.1512; printf("%f", D); return 0; } 程序运行结果: 47 第第3 33章 章 按 部 就 班 顺 序 结 构 程 序 设 计 1512.000000 【应用扩展】 本实例中,如果汇率不变,已知有5000美元,请问可以兑换多少人民币呢? 3.出国货币兑换 随着我国经济的快速增长,人们的生活水平日益提高,越来越多的人选择出国旅游以增 长阅历,但要在异国消费,首先便是兑换目的旅游国的货币。假如,你要携带父母到美国旅 游,已知今日的人民币兑换美元的汇率为rate,请编程实现给定任意的人民币x,计算可以 兑换多少美元y。 【问题分析】 本问题的求解关键是要找到人民币与美元之间的换算公式。由于货币汇率是指两种不 同货币之间的兑换价格,若已知人民币兑换美元的汇率为rate,则人民币x 与美元y 的兑换 公式为y=x×rate。 图3-8 外部兑换算法流程图 【问题求解】 根据问题分析所得人民币与美元的兑换公式, 可以在给定汇率下,对任意的人民币完成与美元之 间的兑换,其算法流程如图3-8所示。 根据流程图3-8,可以编写相应的C语言程序 代码如下: 综合案例3:货币兑换 #include<stdio.h> int main() { double rate, x, y; printf("请输入当前的人民币兑换美元的汇率(大于0 且小于1 的小数):"); scanf("%lf", &rate); printf("请输入所要兑换的人民币金额(大于0 的数):"); scanf("%lf", &x); //根据汇率将人民币兑换成美元 y = x * rate; printf("%.2f 人民币在汇率为%.4f 时可以兑换%.2f 美元\n", x, rate, y); return 0; } 程序运行结果: 请输入当前的人民币兑换美元的汇率(大于0 且小于1 的小数):0.1439 ↙ 请输入所要兑换的人民币金额(大于0 的数):10000 ↙ 10000.00 人民币在汇率为0.1439 时可以兑换1439.00 美元 【应用扩展】 本问题的求解思路可以运用于很多不同单位的数据之间的换算,如重量换算、温度换 算、体积换算等。 4.求三角形的周长和面积 已知直角三角形的两条直角边分别为3和4,求三角形的周长和面积。(3.3节的问题3) 【问题分析】 本题已知直角三角形的两条直角边,欲求直角三角形的周长,必须首先求出三角形的第 48 C语 言 程 序 设 计 面 向 实 践 能 力 培 养 三条边的长度,可利用勾股定理求出。再分别计算三角形的周长和面积。 【问题求解】 综合案例4:求直角三角形的周长和面积 #include<stdio.h> #include<math.h> int main() { int a, b; float c, L, S; //变量c 为直角三角形第三条边,L 为周长,S 为面积 scanf("%d,%d", &a, &b); c = sqrt(a * a + b * b); L = a + b + c; S = 1.0 / 2 * a * b; printf("%f, %f", L, S); return 0; } 程序运行结果: 3,4 ↙ 12.000000, 6.000000 【应用扩展】 由此,我们也可以已知正方形的边长,计算正方形的周长和面积;已知长方形的长和宽, 求长方形的周长和面积;已知圆的半径,求圆的周长和面积等。 5.输出简单的字符图形 请用输出函数输出如图3-9所示的字符图案。 图3-9 菱形和平行四边形图案 【问题分析】 通过观察可知,图3-9(a)中的菱形总共有7行,每行星号(*)的个数依次为1、3、5、7、 5、3、1。从形态上看,每行星号都是居中显示的。图3-9(b)中的平行四边形总共有4行,各 行星号的个数均为10。从形态上看,上一行的第一个星号与下一行的第一个星号相比在前 面多了一个空格。为了能够使输出的星号呈现出题目要求的形态,可以在正式输出每行星 号之前,先输出相应个数的空格符来实现。 【问题求解】 根据以上分析,借助流程图绘制软件可以作出相应的算法流程图,如图3-10所示。 根据算法流程图,可以写出相应的C语言实现代码。显示图3-9(a)中的菱形图案的C 语言代码如下: 49 第第3 33章 章 按 部 就 班 顺 序 结 构 程 序 设 计 图3-10 算法流程图 综合案例5(a):显示图3-9(a)中的菱形 #include<stdio.h> int main() { printf(" *\n"); //输出第1 行的星号,前面有3 个空格 printf(" ***\n"); //输出第2 行的星号,前面有2 个空格 printf("*****\n"); //输出第3 行的星号,前面有1 个空格 printf("*******\n"); //输出第4 行的星号,前面有0 个空格 printf("*****\n"); //输出第5 行的星号,前面有1 个空格 printf(" ***\n"); //输出第6 行的星号,前面有2 个空格 printf(" *\n"); //输出第7 行的星号,前面有3 个空格 return 0; } 显示图3-9(b)中的平行四边形图案的C语言代码如下: 综合案例5(b):显示图3-9(b)中的平行四边形 #include<stdio.h> int main() { printf(" **********\n"); //输出第1 行的星号,前面有3 个空格 printf(" **********\n"); //输出第2 行的星号,前面有2 个空格 printf("**********\n"); //输出第3 行的星号,前面有1 个空格 printf("**********\n"); //输出第4 行的星号,前面有0 个空格 return 0; } 【应用扩展】 本问题的算法核心是充分运用printf函数输出数据时的格式控制能力,结合输出前导 空格和回车换行,可以打印各式各样的图案。但现在的这种实现方式在打印很大的图案时 会显得很烦琐,在学习完循环结构程序设计之后,我们可以用更有效的方法来实现。 6.简易计算器菜单 请用输出函数实现在命令行提示符窗口中输出简易的计算机菜单,如图3-11所示。 图3-11 简易的计算机菜单 50 C语 言 程 序 设 计 面 向 实 践 能 力 培 养 【问题分析】 题目中要求输出的简易计算机菜单信息都是由普通字符串构成,使用printf函数来输 出即可。每个菜单项和提示信息各自占据一行,则可以通过回车换行来实现。 【问题求解】 根据问题分析可以写出相应的C语言代码如下: 综合案例6:输出菜单 #include<stdio.h> int main() { printf("==========简易计算器==========\n"); printf("1. 加法运算\n"); printf("2. 减法运算\n"); printf("3. 乘法运算\n"); printf("4. 除法运算\n"); printf("您要执行的运算是(请输入上述菜单项前的编号):"); return 0; } 【应用扩展】 在一个完整的C语言应用程序中,通常包含有多个功能模块,为了提供更加人性化的 功能,一般都会给出一个功能菜单供用户选择所要执行的操作。 7.交换两个瓶中的液体 有两个瓶子A 和B,分别盛放醋和酱油,要求将它们互换(A 瓶原来盛放醋,现改盛酱 图3-12 算法流程图 油,B瓶则相反)。 【问题分析】 要使A、B容器所盛的液体互换,关键是需要借助一个空的容器 C(假定3个容器的大小相同,避免液体溢出)来暂存交换中的液体。 具体交换步骤:先将A 中的液体倒入C 中,再将B 中液体倒入A 中,最后将C中的液体倒入B中。 【问题求解】 根据以上分析,借助流程图绘制软件可以画出相应的算法流程 图,如图3-12所示。 根据问题分析可以写出相应的C语言代码如下: 综合案例7:互换两个瓶子A 和B中的液体 #include<stdio.h> int main() { int a, b, c; //代表三个同样的瓶子 printf("请输入两个整数:"); scanf("%d%d",&a,&b); c = a; a = b; b = c; printf("交换后的结果是:%d %d\n",a,b); return 0; }