《程序设计与C语言》课件第4章_第1页
《程序设计与C语言》课件第4章_第2页
《程序设计与C语言》课件第4章_第3页
《程序设计与C语言》课件第4章_第4页
《程序设计与C语言》课件第4章_第5页
已阅读5页,还剩193页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第4章语句及控制结构4.1C语言语句4.2简单语句4.3输入/输出功能语句4.4条件语句4.5循环语句4.6转向语句习题44.1C语言语句

C语言中,语句的含义也非常广泛。任何数据成分,只要以分号结尾,就称为语句,甚至只有一个分号也称为语句(空语句)。分号是C语言中语句的标志。一个语句可分写成多行,只要未遇到分号就认为还在同一个语句中;反之,在一行中也可以写多个语句。也就是说,C程序的书写是相当自由的。不过为了醒目起见,最好一行只写一条语句,并且根据不同的语法成分,错落有致地加以排列,这样会更好地增加程序的可读性。本章我们将详述C中的语句。在学习一种语言时,要对其使用的语法规则、语义含义等深刻理解,灵活运用。表4-1中先给出了C语言中语句的类别、名称及一般形式。4.2简单语句4.2.1空语句空语句在程序中只用一个分号表示:;它什么也不做。它主要用在:①转向语句的转向点;②循环语句的循环体。若循环体为空,则其循环的动作全在循环头中进行。4.2.2表达式语句表达式是由运算符和运算对象构成的式子,本身并没有执行的功能,但如果在它的后面加上一个分号,就变成了语句,可以被执行了。虽然表达式的种类很多,但最常见的表达式语句多为赋值语句和函数调用语句。例如:i=3;x=PI*r*r;++i;printf(″Hello!″);其中前三个为赋值语句,第四个为函数调用语句。

x+3;也是个表达式语句,实现x和3相加,但它未改变x的内容,也未引起其他变化,因此对这个语句的执行没有实际意义。

【例4-1】交换两个变量的值。

解题思路:要交换两个变量的值,必须借助第三者。设有两个变量a和b,当把a的数据直接赋给b时就会破坏b中的内容,而通过第三个变量作中间过渡,就可以避免这种情况的发生,如图4-1所示。图4-1交换两个变量值的示意图程序实现如下:#include<stdio.h>main(){inta,b,c;a=4,b=8;printf(″a=%d,b=%d\n″,a,b);c=a;a=b;b=c;printf(″a=%d,b=%d\n″,a,b);return0;}运行输出:a=4,b=8a=8,b=4其中,a=4,b=8;是逗号表达式(包含了赋值)语句。在前后两个表达式的运算互不相关的时候,可以用逗号运算符把它们连起来,当然也可以用分号。4.2.3复合语句把多条语句用花括号括起来即构成所谓的复合语句,例如:{sum=sum+i+j;i++;j--;}复合语句对内部来说有多条语句,对外部来说它又是一个整体,算是一个语句。复合语句通常用做循环语句的循环体或条件语句的分支。例如,在上例中假设只有在a大于b时才交换它们的值,则可以写为if(a>b){c=a;a=b;b=c;}4.3输入/输出功能语句

C语言没有提供专门的输入/输出语句,但是却提供了有输入/输出功能的函数,通过函数调用就可以达到输入/输出的目的。函数属于表达式的一部分,因此函数调用语句也是表达式语句的一种。要使用这些输入/输出函数,必须要把有关函数的信息告诉程序。告诉的方法是在程序头部加上#include<stdio.h>说明。“stdio.h”是一个头文件,stdio代表“standardinputandoutput(标准输入/输出)”,即用系统提供的标准输入/输出设备来进行输入/输出。标准输入设备有键盘,标准输出设备有屏幕、打印机等。扩展名“h”代表head,说明该文件是头文件。#include是包含,它表示在编译以前先把头文件stdio.h包含进来,程序中就可以使用标准输入/输出函数了。4.3.1字符输入/输出功能语句

1.getchar函数该函数形式为:

getchar()

getchar是函数名,后面圆括号内是空的,说明该函数没有参数。该函数的使用形式是:

〈字符变量〉=getchar();其功能是从键盘上敲入一个字符,然后把它赋给字符变量。需注意的是,所键入的字符并不立即赋给字符变量,只有在输入一个回车符后,字符变量才能得到字符。要想使字符变量立即得到所键入的字符,可用getch()函数。单独调用getchar()函数不能得到字符,但有其他用途,比如在程序的最后增加getchar();语句,可便于在用户界面观察程序的执行结果。

2.putchar函数该函数形式为:

putchar(〈字符对象〉)

putchar是函数名,其参数可以是一个字符常量或字符变量。该函数的功能是向终端输出一个字符。因整型和字符型是通用的,所以putchar函数也能够把代表某个字符编码的整数作为一个字符输出。

【例4-2】字符输入/输出。#include<stdio.h>main(){charch1,ch2,ch3;ch1=getchar();ch2=getchar();ch3=getchar();putchar(ch1);putchar(′′);putchar(ch2);putchar(′′);putchar(ch3);putchar(′\n′);putchar(′\101′);putchar(66);putchar(′\″′);putchar(′\n′);return0;}运行程序: 输入: abc↙

输出为: a└┘b└┘c AB″其中,′\101′是′A′的八进制编码,66是′B′的十进制编码,输出结果中的表示一个空格,下同。注意:

如果输入时按了空格键或回车键,则getchar函数会把空格符或换行符作为字符读入。有时还可以直接用getchar和putchar输入和输出字符,不需要再定义一个字符变量,例如:

putchar(getchar());此时,getchar()函数作为putchar()函数的参数被调用,它输入的字符不经转手就被putchar输出了。4.3.2格式化输入/输出功能语句

getchar、putchar函数只能对字符进行输入/输出,而对其他类型的数据就必须用格式输入/输出函数进行输入/输出。

1.printf函数这是一个格式化的输出函数,它使用的一般格式是:

printf(〈控制格式〉,〈输出列表〉)前面我们已知,输出的对象必须有相应的控制字符限定修饰才能输出,那么C中都有哪些控制字符呢?我们在这里主要介绍以下控制字符:d,o,x,u,c,s,f,e,g,p。不同的控制字符用以输出不同类型的数据。表4-2给出了要输出的数据类型与其控制格式之间的对应关系。

1)%d格式

(1)%d格式用来输出十进制整数,按数据的实际长度输出。

(2)可以对输出数据所占字节位数加以限制,方法是在%和d之间加一整数,整数可正可负。正整数表示输出数据在所给空间中右对齐,左边留出空格;负整数表示左对齐,右边留出空格。当输出数据位数大于所给空间时,则可突破位数的限制,按其实际大小全部输出,例如:

printf(″a=%5d″,13); 输出为:a=└┘

└┘

└┘13 printf(″a=%-5d″,13); 输出为:a=13└┘

└┘

└┘

printf(″a=%3d″,12345); 输出为:a=12345

(3)%ld格式。当输出的数据大于32767时,不能再用%d格式,这时应该用长格式%ld输出。例如:

printf(″a=%ld″,1234567);的输出为:a=1234567。也可以对长格式的位数加以限制,方法如(2)。

2)%o格式

%o以八进制形式输出整数,其机理是把整数在内存中的ASCII编码由低位向高位三位一组进行分节,每一节用一个八进制数码表示,这样如果原来的数据为负,则符号位的1也被作为八进制数的一部分加以处理了。例如:

inta=-1; printf(″%d,%o\n″,a,a);的输出为:-1,177777。a=-1的内存形式为因此,用八进制格式输出整数时以正整数为宜。1111111111111111

3)%x格式(或%X)

%x以十六进制形式输出整数,其机理和八进制输出一样,只是它将对二进制编码按四位一组进行分节,每节用一个十六进制数码表示,同样也不考虑符号。如:inta=-1;printf(″%d,%o,%x\n″,a,a,a);的输出为:-1,177777,ffff。

4)%u格式

%u以十进制形式输出无符号整数。可以用%u格式输出定义为其他整数类型的数据,用其他输出整数的格式也可以输出定义为无符号整数的数据,只是要注意,这两种情况只能在正整数的区间内使用。

【例4-3】格式化输出。#include<stdio.h>main(){inti=-2;unsignedintu=65535;printf(″u=%d,%o,%x,%u\n″,u,u,u,u);printf(″i=%d,%o,%x,%u\n″,i,i,i,i);return0;}运行输出:u=-1,177777,ffff,65535i=-2,177776,fffe,65534由例4-3的运行输出可以看出,%u格式是把最高位也作为数值位处理的,而%d格式是把最高位当成符号位来处理的。

5)%c格式

%c格式输出一个字符,和字符ASCII编码对应的整数也以字符形式输出,并可以为其指定长度。例如charc=′a′;printf(″c=%c,%c\n″,c,97);printf(″c=%5c\n″,c);则结果为:c=a,ac=└┘└┘└┘a

6)%s格式

%s格式用来输出字符串。

(1)%s格式按实际大小输出字符串,但若字符串中含有′\0′字符,则输出到′\0′截止,即并不把双引号中的内容全部输出。例如:

printf(″s=%s\n″,″China″);输出:s=China printf(″s=%s\n″,″China\0Japan″);输出:s=China字符′\0′后的内容被舍掉,′\0′本身也不输出。如果字符串中有控制字符,则控制字符也会发挥作用。例如:

printf(″%s\n″,″China\nJapan″);则输出为:

China Japan

(2)指定输出字符串的长度,规则如前。例如:

printf(″s=%6s″,″book″);输出:s=└┘└┘book(右对齐) printf(″s=%-6s″,″book″);输出:s=book└┘└┘(左对齐) printf(″s=%2s″,″book″);输出:s=book(突破限制)

(3)输出字符串前端的部分字符格式%<m>.<n>s。这种格式指明:在m列宽度中输出字符串的前n个字符,当m<n时,有m=n。例如:

printf(″s=%5.3s″,″China″);输出:s=└┘└┘Chi printf(″s=%-5.3s″,″China″);输出:s=Chi└┘└┘

printf(″s=%2.3s″,″China″);〖HT5SS]输出:s=Chi

7)%f格式

%f格式以小数形式输出单精度、双精度类型的浮点数。

(1)以%f格式输出浮点数时,整数部分全部输出,小数部分输出6位,但输出的不一定全是有效数字。对单精度数只有左边7位有效,而对双精度数只有前16位有效。

(2)也可以指定输出的宽度和小数位数,例如:

printf(″f=%10.2f\n″,123.456);输出:f=└┘└┘└┘└┘123.46输出宽度中包含小数点位数,小数部分进行四舍五入。

printf(″f=%-10.2f″,123.456);输出:f=123.46 printf(″f=%1.2f″,123.456);输出:f=123.46└┘└┘└┘└┘当所给宽度小于数据位数时会自动突破位数的限制,这时数据的整数部分全部输出,小数部分按要求输出。

8)%e格式(或%E)

%e格式以指数形式输出浮点数,包括单精度数和双精度数。输出时,尾数的整数部分只有1位,系统自动指定尾数的小数部分的宽度和指数部分的宽度。对此不同的系统有不同的规定。对TurboC来说,小数部分6位,指数部分4位(包括字母e或E,1位阶符,2位阶码)。例如:

printf(″f=%e″,123.456);输出:f=1.234560e+02也可以指定输出宽度和尾数的小数位数:

printf(″f=%10.2e″,123.456);输出:f=└┘└┘1.23e+02同样,当总宽度定义得小时会被突破。当有小数部分时,输出至少要用6位:尾数的整数1位,小数点1位,指数部分的4位。这6位再加上小数部分指定的位数,即为实际使用的位数,例如:

printf(″f=%6.2e″,123.456); 输出:f=1.23e+02输出占用了8位。

9)%g格式(或%G)

%g格式用于输出尾数中不带无效0的浮点数,以尽可能地少占输出宽度。例如:

printf(″g=%g″,123.4); 输出:g=123.4这种输出更符合人们的阅读习惯。

10)%p格式

%p格式用于输出变量的地址,而变量的地址是由编译程序分配的。通过查看变量的地址,可以知道变量在内存中的相对位置。例如:

inta,b; printf(″&a=%p,&b=%p\n″,&a,&b);输出:&a=FFD4, &b=FFD2

11)对printf函数控制字符的进一步说明

(1)以上介绍了10种控制字符的一般用法,为了满足特殊的要求,还可以对控制字符加一些特殊的修饰。修饰符或标志共有6种,如表4-3所示。标志的具体用法看下面的例子。

【例4-4】标志的具体用法。#include<stdio.h>main(){printf(″%+d\t%+d\n″,786,-786);/*输出:+786-786*/printf(″a=%d\ta=%d\n″,5,-5);/*输出:a=5a=-5*/printf(″%#o\n″,1427);/*输出:02623*/printf(″%#x\n″,1427);/*输出:0x593*/printf(″%g\n″,1427.00);/*输出:1427*/ printf(″%#g\n″,1427.00);/*输出:1427.00*/ printf(″%+09d″,125);/*输出:+00000125*/ printf(″%*.*f″,7,2,87.4573);/*输出:87.46*/ printf(″%-+09d″,125);/*输出:+125,此时0占位符不起作用,只有在域宽大于数据位数且是右对齐时,0占位符才起作用*/ return0; }其中:″%+09d″中的9是输出总域宽,包括在正数前所加的“+”字符,0表示用0来填充;printf(″%*.*f″,7,2,87.4573);中的*号表示的数值是由后面的参数提供的,两个*号分别和7、2相对应,也就是″%7.2f″这样的格式。采用格式串中用不定宽度表示而后由参数确定的格式有一定的灵活性。

(2)精度说明。我们已介绍过用%f和%e对浮点数的输出作精度说明,同样对%d和%g控制符我们也可以作精度说明。

%d的精度说明是指至少要打印的数字位数,例如:

printf(″%.9d″,123);输出:000000123多余的位数用0填充。

%g的精度说明是指输出的有效数字的最大位数,例如:

printf(″%.3g″,12.389);输出:12.4

(3)程序中易出现的错误:①把除%X、%G、%E外的控制字符写成大写,如%D等。②试图用%c格式输出字符串的第一个字符。如:

printf(″%c″,″China″);这样输出不了′C′。③试图用%s格式输出字符。如:

printf(″%s\n″,′a′);结果也是错误的。

2.scanf函数

scanf函数能对各种类型的数据变量进行格式化输入。

scanf函数的一般格式为:

scanf(〈控制格式〉,〈输入列表〉)前面我们已知,scanf的输入列表中是以逗号分开的变量的地址,即每个变量名前面必须加一个地址运算符&。而在控制格式串中必须有和后面地址相对应的控制字符,里面还可以出现非控制字符,如果出现有非控制字符,则在输入时必须也把它们输入,否则就会发生输入错误。例如:inta,b,c;scanf(″%d,%d,%d″,&a,&b,&c);格式控制串中除有三个格式控制符%d外,还有两个逗号,这两个逗号在输入时也必须输入,即必须按如下格式输入:

3,4,5↙

如果输入时以

345↙形式敲入,则会出现错误。为了避免这种错误,在控制串中最好不要加入其他成分,以免在输入时忘掉或不匹配。如果在输入格式控制串中没有其他字符,如:

scanf(″%d%d%d″,&a,&b,&c);则输入时就可以非常灵活多样。例如,可以作

3└┘└┘4└┘└┘5↙这样的输入,也可以随意换行,作

3↙ 4└┘└┘5↙这样的输入,只要能把两个整数分开即可。表4-4列出了输入的数据与其所用的控制符之间的对应关系。在表4-4中的基本输入控制符之前还可以再加如表4-5所示的修饰符。例如:

inta,b; scanf(″%2d%*3d%*2c%2d″,&a,&b);若输入:

12345&&67↙

则结果为a=12,b=67。%*3d会把345舍掉,%*2c会把&&舍掉。应注意,和%*3d对应的应该是三位数字,和%*2c对应的应该是两个字符。这种方法主要用于对已有数进行选取,一般不用。注意:

(1)用′%c′格式输入时,敲入的任何字符,包括空格,均作为有效字符输入。

(2)用scanf输入时,应做到变量类型、输入格式和输入数据三者相一致。例如有变量定义:inta,b,c;longintl1,l2,l3;floatx,y,z;doubled1,d2,d3;

①输入数据和控制格式不一致时会出错。例如对于

scanf(″%d%d%d″,&a,&b,&c);输入:

23.4└┘65└┘71.8↙

则a、b、c均无正确的整数值。②用短格式输入长变量时会出错,如scanf(″%d%d″,&l1,&l2);scanf(″%f%f″,&d1,&d2);③用长格式输入短变量时也会出错,如

scanf(″%ld%ld″,&a,&b);scanf(″&lf&lf″,&x,&y);④对长变量只能用长格式进行输入,下面的写法是正确的:

scanf(″%ld%ld″,&l1,&l2);scanf(″%lf%lf″,&d1,&d2);对格式化输入/输出的具体细节在上机时应多加注意和练习,这样才能逐渐明白和掌握。

【例4-5】输入一个字符,求其先导字符和后继字符。

编程思路:对字符的输入,既可以用getchar函数,也可以用“%c”控制格式;输出时既可以用putchar函数,也可以用“%c”作格式输出。字符是有序类型,故可求其先导和后继,前后字符的ASCII编码相差为1。#include<stdio.h>main(){charc,ch,pre,pos;c=getchar();pre=c-1;putchar(pre);putchar(′,′);putchar(c);putchar(′\n′);scanf(″%c″,&ch);pos=ch+1;printf(″%c,%c″,ch,pos);return0;}运行输出:ii↙

h,ii,j

注意:输入时一定要敲入两个字符再按回车键,这样一个字符给变量c,一个字符给ch。如果只输入一个字符就按回车键,则把这个字符交给了变量c,而把回车符交给了变量ch,它就输出不出来了。凡涉及字符输入时都要考虑这种情况。

【例4-6】输入一个球的半径,求其体积;输入一个圆柱体的底面半径和高,求圆柱体的表面积。

编程思路:①找出和问题有关的量,每个量用一个变量表示。本题需要定义5个变量:球半径rg,球体积volume,圆柱底面半径rs,高h,表面积area。②写出数学公式:③把代数公式转换成C语言的表达式形式:volume=4*π*rg*rg*rg/3area=2*π*rs*rs+2*π*rs*h④C语言中没有π这个字符,必须用一个常数代换它,因为对它要使用多次,所以可以把它定义为符号常量,方法如下: #definePI3.141593于是可写出程序如下:

#include<stdio.h>#definePI3.141593main(){floatarea,volume,rg,rs,h;printf(″Inputradiumofglobal:\n″);

scanf(″%f″,&rg);volume=4*PI*rg*rg*rg/3;

printf(″Inputradiumandhightofcolumn:\n″);scanf(″%f%f″,&rs,&h);area=2*PI*rs*rs+2*PI*rs*h;printf(″Thevolume=%10.2f\n″,volume);printf(″Thearea=%-10.2f\n″,area);return0;}运行输出:

Inputradiumofglobal: 3.5↙

Inputradiumandhightofcolumn:

4.24.5↙

Thevolume=└┘└┘└┘└┘179.59(右对齐) Thearea=229.59└┘└┘└┘└┘(左对齐)

【例4-7】输入一个三位数,分别以十进制格式(%d)和字符格式(%c)输出其百位、个位、十位数字。编程思路:①首先运用求模(%)和整除(/)运算求出个位、十位、百位上的数字。②根据数字和相应数字字符之间的关系确定与个位、十位和百位上的数字对应的字符。数字和相应数字字符的关系如下: 数字+′0′=相应数字字符如7+′0′=′7′,9+′0′=′9′。程序如下:#include<stdio.h>main(){intn,ge,shi,bai;printf(″Inputaninteger:\n″);scanf(″%d″,&n);ge=n%10;shi=(n/10)%10;bai=n/100;printf(″bai:%d\n″,bai);printf(″digit:%d%d%d\n″,bai,shi,ge);printf(″chara:%c%c%c\n″,bai+′0′,shi+′0′,ge+′0′);return0;}运行输出:Inputaninteger:379↙

digit:379chara:3794.4条件语句

C语言中有两种条件语句:双分支的if语句和多分支的switch语句。根据不同的情况恰当地使用它们,可以提高编程效率。4.4.1if语句

1.if语句的一般形式

if语句的一般形式是:

if(〈表达式〉)〈语句1〉else〈语句2〉

if语句的语义如图4-2所示。图4-2if语句的语义首先对表达式求值,若值为真就执行语句1,否则就执行语句2。

说明:

(1)语句1和语句2可以是简单语句,也可以是复合语句。else前若是简单语句则必须由分号结束,不要认为分号会把整个if语句拦腰截断,事实上不加分号在C语言中反而是错误的。

(2)语句2也可以没有,这时的if语句结构称为单路结构;若两个分支都有则称为双路结构。

【例4-8】输入三角形的三边,求三角形的面积。编程思路:①定义4个变量a,b,c和area,分别表示三角形的三条边与面积。②由三边求三角形面积的公式是:其中,在C语言中写为s=(a+b+c)/2。开平方要调用C语言提供的内部函数sqrt(),有关这个函数的性质在math.h头文件中说明,因此在程序中应该把这个头文件包含进来。③根据数学知识,三角形任意两边之和大于第三边,因此对输入的三边必须进行判断,以保证输入的三边能够构成一个有意义的三角形。程序如下:#include<stdio.h>#include<math.h>main(){floata,b,c,area,s;printf(″Input3edges:\n″);scanf(″%f%f%f″,&a,&b,&c);if(a+b>c&&b+c>a&&a+c>b){s=(a+b+c)/2;area=sqrt(s*(s-a)*(s-b)*(s-c));printf(″Thearea=%.2f″,area);}elseprintf(″Inputerror!\n″);return0;}运行输出:Input3edges:237↙

Inputerror!再运行一次:Input3edges:357↙Thearea=6.50

2.if语句的嵌套在if语句中,它的任一分支又可以是一个if语句,这样就形成了嵌套的if语句,其一般形式为:if(〈条件1〉)〈语句1〉elseif(〈条件2〉)〈语句2〉

elseif(〈条件n〉)〈语句n〉else〈语句n+1〉其语义如图4-3所示。图4-3嵌套的if语句的语义

写嵌套的if语句时应注意以下问题:

(1)if和else应配对出现,每一个else和离它最近且尚未匹配的if相匹配。

(2)应在条件为真时执行一个操作,而在条件为假时再去测试下一个条件。不要在某条件成功后再接着去测试下一个条件,这样做的话,在嵌套层次数多时会失去智力上的控制,即不要写成下面的形式:if〈条件1〉if〈条件2〉if〈条件3〉

else…else…else…

(3)在嵌套的多个条件中,应尽量把求值为真的概率最大的条件放在前面优先判断,这样可以提高if语句的运行效率。例如:在学生成绩的登记中,90分以上为A,80~90分为B,70~80分为C,60~70分为D。如果80~90分之间的学生最多,就应先对这个分数段进行处理:if(score>=80&&score<90)printf(″B″);elseif(score>=90){printf(″A″);printf(″Verygood!\n″);} elseif(score>=70) printf(″C″); else printf(″D″);这样写是为了避免在嵌套层数过多时语句不断向右缩而使一行的空间不断减少,从而不得不使语句折行,那样就破坏了程序的可读性,因此我们推荐上面这种写法,即不管嵌套多少层,都使else处在同一列上。在条件score>=90成立的情况下有两条语句,它们构成了复合语句,因此要用花括号括起来,如果缺少花括号,则会出现错误。

【例4-9】输入一个字符,若为数字字符,则输出Number;若为大写字母,则输出Upper;若为小写字母,则输出Lower;若为回车换行符,则输出ReturnLine,其他字符则输出Other。编程思路:①用嵌套的if语句对输入的字符进行连续判断。②C语言中没有集合运算符,要判断一个对象是否属于某个集合,应该列出这个集合的上下界,这要用关系运算符和逻辑运算符来描述范围。程序如下:#include<stdio.h>main(){charch;printf(″Inputacharacter:\n″);ch=getchar();if(ch==′0′&&ch<=′9′)printf(″Number\n″);elseif(ch>=′A′&&ch<=′Z′) printf(″Upper\n″);elseif(ch>=′a′&&ch<=′z′) printf(″Lower\n″);elseif(ch==′\n′) printf(″ReturnLine\n″);elseprintf(″Other\n″);return0;}运行输出:Inputacharacter:A↙

Upper

注意:不能把代数中的不等式简单地搬到C语言中来,如表示大写字母的范围应该写成ch>=′A′&&ch<=′Z′,而不能写成′A′<=ch<=′Z′。

if语句在程序中常见的错误是:①忘记标记复合语句的一个或两个花括号。对嵌套在中间的复合语句来说,这样会引起语法错误;对最后的一个复合语句来说,这样会引起逻辑错误。②if结构的条件部分没有用圆括号括起来,如:ifa>b…。③在if结构的条件部分后面加分号,这样在单路选择中会出现逻辑错误,在双路选择中会出现语法错误。例如:

if(a>b);printf(″OK″):原意为当a大于b时打印OK,现在的情况是不管a是否大于b都打印OK。if(a>b);printf(″Yes″);elseprintf(″No″);这时会出现语法错误。

3.if语句中条件表达式的灵活设置因为C语言中是用非0和0来表示真和假的,所以条件的表示可以有多种形式:

(1)用一个数值表示条件。如:intm;scanf(″%d″,&m);if(!m)printf(″Yes″);其中if(!m)等价于if(m==0)。

(2)将赋值运算和条件判断结合起来。如:charch;if((ch=getchar())!=′\n′)putchar(ch);这里先调用getchar函数,输入一个字符,赋给ch,再判断ch是否为回车符,若不是回车符则将其输出。

(3)用复合的逻辑表达式表示条件。如:

if(score>70&&score<80)printf(″B″);此时常犯的错误是写成数学中的不等式形式:

if(70<score<80)数学中的式子要经过适当改造才能用于C程序中,不能直接照搬。

4.if语句和条件表达式的关系如有条件表达式语句max=a>b?a:b;,其功能是把a、b中的最大者赋给变量max,用if语句来实现即为:if(a>b)max=a;elsemax=b;在条件不太复杂的情况下,用条件表达式比较简单,但如果条件复杂,嵌套层数较多时,还是用if语句为好。在程序设计中,将if语句和条件表达式结合起来使用会使程序变得简练。

【例4-10】猜数游戏。程序预置一个常数(称为幻数),让用户猜,猜对时给出正确信息,否则会给出是大了还是小了的提示。#include<stdio.h>main(){intmagic=618,guess;printf(″Inputyourguess:\n″);scanf(″%d″,&guess);if(guess!=magic)guess>magic?printf(″High″):printf(″Low″);else{printf(″***Right***\n″);printf(″%disthemagicnumber.\n″,magic);}return0;}运行输出:Inputyourguess:600↙

Low再运行:

Inputyourguess: 700↙

High再运行:

Inputyourguess: 618↙

***Right*** 618isthemagicnumber.这里的条件表达式语句相当于一个内嵌的if语句。4.4.2switch语句

if语句是双分支结构,如果要连续地测试多个条件,就需要用嵌套的if语句来实现。如果嵌套层次过多,不仅写起来麻烦,而且还不清晰。对于这类问题,用switch语句可以很好地解决。switch语句是一种多分支结构,其一般形式是:switch(〈表达式〉){case〈常量1〉:〈语句1〉case〈常量2〉:〈语句2〉

case〈常量n〉:〈语句n〉default:〈语句n+1〉}

switch语句的语义如图4-4所示。它的含义是:首先对表达式e进行计算,如果其值是e1,则转去执行语句s1。如s1后面有break语句,则switch语句结束;如s1后面无break语句,则在switch内部继续向下执行s2。如果e的值不为e1,而为e2,则转去执行e2后面的s2语句,执行完s2后的情况如上。如e的值与e1,e2,…,en全不相同,就去执行语句sn+1。处在switch语句中最后位置上的语句,其后面加不加break效果相同,程序执行到此处都会退出switch语句。图4-4switch语句的语说明:

(1)switch语句中的表达式的类型只能是有序类型。

(2)e1,e2,…,en是表达式的求值结果,必须互不相同。

(3)可以有多个常量共同拥有一个语句的情况,如:

case1:case2:case3:printf(″123″);break;

(4)default指出当表达式求值结果和所有常量均不相同时要执行的动作。它的位置可以放在switch中的任何地方,不一定放在最后。

(5)语句si(i=1,2,…,n)可以是一条语句,也可以是多条语句,是多条语句时不必用花括号括起来。

【例4-11】用switch语句输出学生的分数等级。设分数大于等于90分为A等,70~90分为B等(含70),60~70分为C等(含60),60分以下为D等,分数为浮点数。

编程思路:switch后的表达式必须是有序类型而且求出的结果应当是一个个离散的值,而不是一个数值范围。应该想办法把一个范围转换成一个确定的值,这是使用switch语句的关键。在这里我们可以把分数除以10再取整,即可变成离散的数值,就可以用switch语句解决了。#include<stdio.h>main(){inti;floatscore;printf(″Inputascore\n″);scanf(″%f″,&score);i=score/10;

switch(i){case9:case10:printf(″A″);break;case7:case8:printf(″B″);break;case6:printf(″C″);break;default:printf(″D″);}return0;}运行输出:Inputascore87.5↙

B再运行:Inputascore99.8A输入的分数是实数,但通过赋值语句就变成了整型,整型是有序类型,并且i具有有限的离散值。printf(″D″);语句后面可以不要break,但如果把其他地方的break全去掉,则当输入分数95.9时,会连续地输出ABCD,因此一定要注意break的使用。4.5循环语句到目前为止我+们所遇到的程序都是简单程序,解决的问题都很简单。要解决复杂问题,并充分发挥计算机快速的优势,那么程序中很可能要用到循环语句。掌握好循环语句就可编出高质量的程序。C语言提供了三种循环语句:for语句、while语句和do_while语句。下面分别加以讨论。4.5.1for语句

for语句的基本形式如下:

for(〈表达式e1〉;〈表达式e2〉;〈表达式e3〉)〈语句s〉其中,表达式e2的类型为逻辑型,表达式e1和表达式e3都不是逻辑型,在其中不能使用比较运算符与逻辑运算符。

for语句的语义如图4-5所示。它的含义是:首先对表达式e1求值,然后判断表达式e2是否为真,如为真就去执行语句s,接着对表达式e3求值,再回去判断e2,直到e2为假时退出for循环。先看一个简单的例子。图4-5for语句的语义

【例4-12】求1~100之间所有奇数之和。#include<stdio.h>main(){inti,sum=0;for(i=1;i<=100;i+=2)sum+=i;printf(″sum=%d\n″,sum);return0;}运行输出:

sum=2500在该例的for循环头中有三个表达式,它们被两个分号分开。循环头的组成部分如下:循环控制变量控制变量的终值↓ ↓

for(i=1;i<=100;i+=2) ↑↑↑for关键字控制变量初值递增控制变量可以看出能否循环是由循环控制变量决定的。一进入循环,首先对控制变量置初值,这个初值是否合适,还要由表达式e2对它进行判断,只有在e2为真的情况下才能去执行循环体。若一开始条件就假,则循环体一次也不执行。在每次循环之后,控制变量的值都要加以改变,这个改变量是决定能否继续循环或是否会无穷循环的关键,一定要使它的值逐渐向循环终值方向变化。当表达式e3计算完之后,再回来计算表达式e2,若e2为真则继续循环,否则退出循环。for循环头中的三个表达式可以缺省,可以缺一个,缺两个,甚至三个全缺,但不管怎么缺,其中的两个分号不能缺,而且这三个表达式的功能也一定要在或前或后的其他地方以其他的形式表现出来。另外,在表达式e1

和表达式e3

的地方可以只有一个表达式,也可以有多个用逗号分开的表达式,并且还可以包含和循环无关的其他表达式。下面是几种不同的表示方法:

(1)表达式e1

和表达式e3

是逗号表达式,如intsum,i;for(sum=0,i=1;i<=100;i++,i++)sum+=i;其中sum=0和循环控制变量无关。

(2)省略表达式e1

和表达式e3,如intsum=0,i=1;for(;i<=100;){sum+=i;i+=2;}表达式e1移到了for语句前,而表达式e3则移到了for循环体中。

(3)三个表达式全部省略,如intsum=0,i=1;for(;;){sum+=i;i+=2;if(i>100)break;}表达式e1移到了for语句前,而表达式e2和表达式e3的功能全部在循环体中。

(4)省略循环体,把循环体变成空语句,原来的工作放到循环头中完成,如intsum=0,i;for(i=1;i<=100;sum+=i,i+=2);这时应注意,原循环体中的语句一定要放在控制变量增值之前,否则就会出错。虽然以上几种写法都是可以的,但为了程序清晰起见,我们不主张这样使用,在for循环头中应只放置和控制变量有关的表达式,而其他的操作应放在循环之前或循环体中。

【例4-13】计算复利。某人在银行存入10000.00元钱,存期8年,年利率为3.5%,求其每一年的存款额。计算复利的公式是:a=p(1+r)n。其中:

p:本金,初始存款值 r:利率

a:n年后的存款数 n:年数#include<stdio.h>#include<math.h>main(){intn;doublea,p=10000.00,r=0.035;printf(″%s%21s\n″,″Year″,″Amount″);

for(n=1;n<=8;n++)

{a=p*pow(1+r,n);printf(″%4d%21.2f″,n,a);}return0;}运行输出:YearAmount1 10350.002 10712.253 11087.184 11475.235 11876.866 12292.557 12722.798 13168.09程序中引用了一个内部数学函数pow(x,y),其功能是求x的y次方,因此应把包含其信息说明的头文件math.h包含进来。

【例4-14】求序列前20项之和。

编程思路:首先从观察序列中每一项的组成及前后项之间的关系入手。发现除首项外,每一项的分子都是前一项的分子与分母之和,而每一项的分母又等于前一项的分子,因此可以很容易地从前一项求出后一项,而第一项可以直接设置。另外,虽然每项的分子、分母都是整数,但考虑到C语言中整除的特点,必须把它们定义成浮点类型。又因循环次数已知,故选用for循环语句。程序如下:#include<stdio.h>main(){

floatsum=0,num=2,den=1;inti;for(i=1;i<=20;i++){ sum+=num/den; num+=den; den=num-den;}printf(″Thesum=%.2f\n″,sum);return0;}运行输出:

Thesum=32.664.5.2while语句

while语句的基本形式为:

while(〈表达式e〉) 〈语句s〉

while语句的语义如图4-6所示。其含义是:首先计算表达式e的值,只要其值为真就执行循环体语句s,直到表达式e求值为假,然后退出循环。在循环体中,一定要对循环控制变量进行修改。图4-6while语句的语义

【例4-15】求1~100之间所有偶数之和。#include<stdio.h>main(){intsum,i;sum=0;i=2;while(i<=100){ sum=sum+i; i+=2;}printf(″sum=%d\n″,sum);return0}运行输出:

sum=2550

while语句多用在循环次数预先难以确定的循环中,如下例所示。

【例4-16】输入并输出一个字符串,遇“#”结束。#include<stdio.h>main(){charc;while((c=getchar())!=′#′)putchar(c);return0;}运行程序,当输入为:

Thisisastring#↙

则输出为:

Thisisastring程序在执行时并不是输入一个字符后立即把它送到屏幕,而是先放入内存缓冲区中,只有在打了回车符之后才把缓冲区里的内容一块输出。

【例4-17】输入一个字符串,去掉所有的前导空格,并将其余地方的多个连续空格压缩为一个空格。例如

″└┘└┘└┘└┘This└┘└┘└┘is└┘└┘└┘a└┘└┘└┘└┘program″压缩为

″Thisisaprogram″

编程思路:可考虑用双重循环解决。外循环用以输入整个字符串,内循环处理连续的空字符。因整个字符串的长度和连续的空格数都是不确定的,因此可用while循环语句。当输入一个空格字符时,用循环语句把可能连续的空格都读出来,但不输出,直到输入一个非空格字符时才输出一个空格,此时内循环结束,并输出最近读入的非空格字符。程序如下:#include<stdio.h>main(){charch;printf(″Inputastring:\n″);while((ch=getchar())==′′);//去掉前导空格putchar(ch);while((ch=getchar())!=′\n′){ if(ch==′′) {while(ch==′′) ch=getchar(); putchar(′′); } putchar(ch); }putchar(′\n′);return0;}运行输出:

Inputastring:

└┘└┘└┘└┘This└┘└┘└┘is└┘└┘└┘a└┘└┘└┘└┘program↙

Thisisaprogram

【例4-18】爱因斯坦阶梯问题。设有阶梯,不知其阶数,但知:每步跨两阶最后剩1阶;每步跨3阶最后剩2阶;每步跨5阶最后剩4阶;每步跨6阶最后剩5阶;每步跨7阶正好到楼顶,求阶梯共有多少阶。编程思路:本题拟采用穷举法求解:从整数1试起,一旦发现某个整数符合所有条件限制,就算找到了答案。这样逐次加1地测试,虽然是可以的,但这未免也太机械了,我们可以根据条件,找出一个相对快捷的算法。设阶数为n,根据所给的条件有下列关系:①n%2=1;②n%3=2;③n%5=4;④n%6=5;⑤n%7=0。由⑤可知,阶梯数一定是7的倍数,所以测试的初值可以从7开始并且在7的倍数14、21、28、35、…中测试。由①知,阶梯数一定是奇数,则进一步简化测试范围为7,21,35,…,这个数列的公差为14。对这个数列中的数值再用②、③、④式中的条件去检测,符合②、③、④式条件的数即为所求。根据上面的分析,可编程如下:#include<stdio.h>main(){intn=7;while(n%3!=2‖n%5!=4‖n%6!=5)n+=14;printf(″Total=%d\n″,n);return0;}运行输出:

Total=119

注意:while语句的表达式中,‖是或运算符,表示只要有一个等式不成立,表达式就为真,就执行循环体,直到三个等式全成立时为止。

【例4-19】求两个正整数a,b的最大公约数(GreatestCommonDivisor,GCD)。求最大公约数的算法在第一章中已作过介绍,这里直接写出程序。#include<stdio.h>main(){

intu,v,t;

printf(″Input2integers:\n″);

scanf(″%d%d″,&u,&v);while(v){

t=u%v;

u=v;

v=t;}printf(″TheGCD=%d\n″,u);return0;}运行输出:Input2integers:2639↙

TheGCD=13程序中的while(v)等价于while(v!=0)。

请思考:设有while(!e),其中条件!e和下列哪个表达式等价?①e!=0②e==0③e!=1④~e(~是求反运算符)while中的条件是让循环能够进行的条件,要求其值为真。这样要使!e为真,就必须使e为假,所以答案应是②式。

【例4-20】用近似公式求π的近似值,直到时为止(其中n为奇数)。

编程思路:这是个求级数和的问题。解决这类问题时,首先要找出级数的构成规律,即前后项之间的关系,怎样用前项求出后项,这样才便于用循环结构求解。本例中,各项都是分数,分母逐次递增2;各项的符号是正、负相间。于是只要能表示出第i项,则分母加2再乘以-1即可得到第i+1项。接着设定变量,题目中要有表示和、项、分母和符号的4个变量,符号只取1和-1两个值,表示在正负数之间转换。因为不知道循环次数,只知道结束循环的条件,所以选用while语句。程序如下:#include<stdio.h>#include<math.h>main(){ints=1;floatpi=0,t=1,n=1.0;while((fabs(t))>=1e-6){pi=pi+t; /*累加本项t*/n=n+2; /*分母加2,为下一项的分母*/s=-s; /*改变符号,为下一项的符号*/t=s/n; /*求出下一项t*/}pi=pi*4;

printf(″pi=%f\n″,pi);return0;}运行输出:

pi=3.141594说明:

(1)程序中要用到求绝对值的数学函数fabs(),因此要把头文件math.h包含进来。

(2)分母n定义成float类型,是为了保证s/n的值为一实数,否则其值永远为0。

(3)数学中的写法10-6应转换为C语言的表示形式1e-6。4.5.3do_while语句

do_while语句的一般形式为:

do 〈语句s〉 while〈表达式e〉其语义如图4-7所示。进入do_while循环后,首先执行一次循环体,然后再测试表达式e,如其为真则继续执行循环体,直至表达式求值为假。

do_while语句与while语句的差别仅仅在于:while语句是条件判断在前,循环体执行在后,如一开始就不满足条件,则循环体一次也不执行;而do_while语句是先执行循环体,后判断条件,所以它至少执行循环体一次。图4-7do_while语句的语义现在我们再来观察前面的输入字符串的例子,现在要求结束符“#”也要输出出来:#include<stdio.h>main(){charc;do{c=getchar();putchar(c);}while(c!=′#′);return0;}运行,输入字符串:

thisisastring#↙

则输出为:

Thisisastring#↙

【例4-21】输入一个正整数,然后按反向输出。比如输入12345,则输出为54321。

编程思路:输入时一次把一个整数完整地输入,而输出则是一次一个数字地输出,并且要求把最低位先输出,所以首先应该把最低位数字分离出来,然后再分离出下一个最低位数字……怎样才能把最低位分离出来呢?可用对10求模的方法。之后用对10求商的方法求出除掉最低位后的数,作为进一步反向输出的基数。#include<stdio.h>main(){intnumber,digit;printf(″Inputaninteger\n″);scanf(″%d″,&number);do{digit=number%10;printf(″%d″,digit);number/=10;}while(number);printf(″\n″);return0;}运行输出:Inputaninteger12345↙

543214.5.4循环语句的嵌套循环嵌套以构成多重循环,这在解决很多实际问题中是经常遇到的。C语言中的三种循环结构可以互相组合使用。比如下面的一些嵌套形式: ①while() ②do { {

while() do {…} {…} while();

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论