m=c;
例2.解方程ax+b=0,a和b从终端输入
#include
voidmain(void)
{
floata,b,x;
printf(“inputa,b:
\n”);
scanf(“%f%f”,&a,&b);
if(!
a)
printf(“errorininputdata\n”);
else
{
x=-b/a;
printf(“x=%.4f\n”,x);
}
}
如果将其中的else子句写成如下形式
else
x=-b/a;
printf(“x=%.4f\n”,x);
会发生什么情况?
因此正确地使用{}是写if语句时应特别注意的问题。
2.嵌套的if语句
当if子句或else子句又含有一个if语句时,则形成if语句的嵌套,称为嵌套的
if语句或称多重if语句。
例求3个数中的最大值。
if(a>b)
if(a>c)max=a;
elsemax=b;
elseif(b>c)max=b;
elsemax=c;
printf(“max=%.2f\n”,max);
还可以用非嵌套的if语句实现
if(a>=b&&a>=c)
printf(“max=%.2f\n”,a);
if(b>=a&&b>=c)
printf(“max=%.2f\n”,b);
if(c>=a&&c>=b)
printf(“max=%.2f\n”,c);
对于嵌套的if语句,由于if语句有两种形式,因此某些嵌套的if语句语义上可以有两种理解(二义性)。
例如:
if(n>0)if(n>0)
if(a>b)if(a>b)
z=a;z=a;
elseelse
z=b;z=b;
上面两个程序片断相同,因为编译程序约定else与其前面最靠近的且未配对的if配对。
因此上面两程序片断,它们的等价形式为
if(n>0)
{
if(a>b)
z=a;
else
z=b;
}
如果非让else与if(n>0)配对则应写成:
if(n>0)
{
if(a>b)
z=a;
}
else
z=b;
4.3 switch语句
switch语句又称为开关语句,从多种供选择的情况中选择满足条件的一种情况执行的简便而又直观的多分支结构。
if语句是二分支结构,如果要表达两种以上的选择要用嵌套的if语句。
例如计算:
用嵌套的if语句:
if(x>=1)
if(x<2)y=3*x+5;
elseif(x<3)y=2*sin(x)-1;
elseif(x<4)y=sqrt(1+x*x);
elseif(x<5)y=x*x-2*x+5;
如用switch语句实现上述功能:
switch((int)x){
case1:
y=3*x+5;break;
case2:
y=2*sin(x)-1;break;
case3:
y=sqrt(1+x*x);break;
case4:
y=x*x-2*x+5;break;
}
switch语句的一般形式为:
switch(表达式){
case常量表达式1:
语句序列1;
case常量表达式2:
语句序列2;
……
case常量表达式n:
语句序列n;
default:
语句序列;
}
说明:
(1)switch、case、default是关键字,switch是语句标志,case和default只能在switch中使用。
(2)表达式是选择条件,表达式的值必须为整型、字符型或枚举型,且表达式必须用()括起来。
{}括起来的部分是语句体,{}不能省,switch的语句体由多个case和至多一个(可以没有)default组成。
(3)case后面的常量表达式是值为常数的表达式,通常为常量或符号常量。
类型必须和选择条件的类型相同;
(4)同一switch语句中的所有case常量值必须互不相同。
(5)每个case(称为一种情况)下可以有零或多个语句,有多个语句时可以不加{}。
(6)switch执行时,先计算作为选择条件的表达式,并将表达式的值依次和case后面的常量比较,当与某个case的常量值相等时,则执行case后面的语句。
若表达的值与各case的常量值都不相等,在有default的情况下,则执行default后面的语句;否则,不执行switch中的任何语句,此时,switch等价于一个空语句。
注意:
switch语句一旦发现表达式的值与某个case的常量值相等,则从该case后面的第一个语句开始依次执行,执行完这个case的语句之后,自动进入下一个case继续执行,直到switch语句体中的最后一个语句被执行为止。
如果希望执行完一种情况的语句后便跳出switch语句,则要利用break语句或return语句。
break跳出switch语句之后继续执行switch语句后面的语句(如果有),return则立即返回到函数调用处。
例3.从终端输入两个实数,和一个四则运算符(+、-、*、/)执行相应的运算并输出运算结果。
#include“stdio.h”
voidmain(void)
{doublex,y,result;
charop;
intflag;
printf(“inputx,y,op:
\n”);
scanf(“%lf%lf%c”,&x,&y,&op);
flag=1;
switch(op){
case‘+’:
result=x+y;break;
case‘-’:
result=x-y;break;
case‘*’:
result=x*y;break;
case‘/’:
if(y)result=x/y;
elseflag=0;break;
default:
falg=0;
}
if(flag)printf(“reslt=%f\n”,result);
elseprintf(“invalidinputyorop\n”);
}
例4:
输入某年某月,输出该月的天数。
分析:
年year为闰年的条件是:
(!
(year%4)&&(year%100))||!
(year%400)为非0,否则year为平年。
#include“stdio.h”
main()
{intyear,month,days,flat;
printf(“inputyear,month”\n”);
scanf(“%d%d”,&year,&month);
flag=1;
switch(month)
{case1:
case3:
case5:
case7:
case8:
case10:
case12:
days=31;break;
case4:
case6:
case9:
case11:
day=30;break;
case2:
if((!
(year%4)&&(year%100))||!
(year%400))day=29;
elsedays=28;break;
default:
flag=0;
}
if(flag)printf(“days=%d\n”,days);
elseprintf(“invalidinputmonth\n”);
}
输入:
19952
输出:
days=28
注意:
switch语句允许多情况执行相同的语句,但在语法上与PASCAL有不同之处。
例如4、6、9和11月均执行days=30;可以写成:
case4:
case6:
case9:
case11:
days=30;
但不能写成:
case4,6,9,11:
days=30;
也不能写成:
case4,case6,case9,case11:
days=30;
4.4while语句
while是三种循环语句中的一种。
1.while语句的一般形式
while(表达式)
语句;
说明:
(1)while是关键字;“表达式”是循环条件,可以为任何表达式,表达式必须用()标起来;
(2)语句为任何单个语句(包括复合语句、if语句、case语句),称为循环体,循环体是当表达式为真(非0)时要重复执行的语句。
(3)while语句的流程图如右图所示。
执行while语句时,首先计算并测试表达式值,若为非0则执行语句(循环体),然后回到(由向上的流程表示)对表达式的下一次计算和测试;如表达式的值为0则结束循环。
例如:
(1)例如
i=0;
while(i<5)
{printf("i=%d\n",i);
i++;
}
printf("i=%d\n",i);
表达式i<5是循环条件,其中变量i值变化能改变表达式值。
i是循环变量。
语句i=0;给循环变量赋初值。
i++;用于改变循环变量的值。
若无此语句则为死循环。
如:
(2)例如
i=k=1;
while(i<5)
{
k+=i;
printf("i=%d,k=%d\n",i,k);
}
因i<5永为真,产生死循环将无穷输出行
i=1,k=2
i=1,k=3
…
(3)例如
i=0;
while(i=4)
{printf("**\n");
i+=2;
}
无论i值在循环体中如何变化,i=4为永真是死循环。
(4)i=0;
while(i==4)
{printf("i=%d\n"i);
i+=2;
}
进入循环时首先测试i==4的值为假,结束循环。
循环体一次也不执行,无输出。
2.while语句的使用要点
(1)用作循环条件的表达式中必须至少包含一个能够改变表达式值的变量,这个变量称为循环变量。
有返回值的函数调用也看成变量,例如:
while(getchar())这里getchar()代表一个int变量。
(2)在第一次测试表达式的值以前,必须通过适当的方式(输入或赋值)给循环变量赋初值。
(3)在下次测试表达式的值之前(即在循环体中)必须有能够改变循环变量值的语句(赋值或输入),且循环变量值的改变应保证循环条件最终取假值。
3.程序设计举例
例5将输入的正文复制到输出,每次一个字符。
分析:
以E0F为结束标志的字符流称为一个正文,可以包含空白字符,例如空格''和换行字符'\n'.在DOS系统上从终端键入Ctrl+z则getchar函数返回文件结束字符EOF。
#include
voidmain(void)
{charc;
printf("inputatextendofctrl+z:
\n");
c=getchar();
while(c!
=EOF)
{
putchar(c);
c=getchar();
}
}
最后四行语句可简化为:
while((c=getchar())!
=EOF)
putchar(c);
但应注意优先级。
while((c=getchar())!
='?
')
putchar(c);
不等价于
while(c=getchar()!
='?
')
putchar(c);
而while(putchar(getchar())!
='?
');也不等价于:
while(putchar(getchar()!
='?
'));
例6.输入一行字符,按字母、数字和其它字符分成三类,分别统计各类字符的数目(换行字符'\n'不统计在内)。
#include
voidmain(void)
{charc;
intalpha=digit=other=0;
while((c=getchar())!
='\n')
if(c>='a'&&c<='z'||c>='A'&&c<='Z')
alpha++;
elseif(c>='0'&&c<='9')digit++;
elseother++;
printf("alphas=%d\ndigits=%d\nother=%d\n",alpha,digit,other);
}
如输入cast=3,honse=5,sunio8
输出alphas=14
digits=3
other=7
例7.输入一正文,统计正文包含的行数、字数和字符数
分析:
正文的一行是以'\n'为结束标志的字符串。
统计行数就是统计'\n'的数目;统计字数只需对空格字符''、制表字符'\t'和换行字符'\n'统一计数。
#include
#defineIN1
#defineOUT0
voidmain(viod)
{
intc,nl,nw,nc,state;
state=OUT;
nl=nw=nc=0;
printf("inputatextendofctrl+Z:
\n");
while((c=getchar())!
=EOF)
{++nc;
if(c=='\n')++nl;
if(c==’’||c==’\n’||c==\’t’)
state=OUT;
elseif(state==OUT)
{state=IN;
++nw;
}
}
printf(“line=&dwords=%dcharacters=%d\n”,nl,nw,nc);
}
由于字与字之间可能包含一个以上连续的空白字符,当遇到每个字的第一个字符时对字计数,state起一个标志作用,它让程序能够识别当前字符是否处于一个字的第一个字符。
IN和OUT表示当前字符在一个字中和不在一个字中两种状态。
例8:
求计算机的字长。
分析:
求机器的字长即计算一个存储int变量时所拥有的二进制位的数目。
#include“stdio.h”
voidmain(void)
{unsignedword;
intn;
word=~0;
n=1;
while(word>>=1)
++n;
printf(“word=length=%d\n”,n)
}
4.5for语句
for语句是比while语句功能更强的一种循环语句。
给循环变量赋初值、测试及修改都在for的控制部分。
甚至循环体也可放到循环的控制部分。
1.For语句的一般形式:
for(表达式1;表达式2;表达式3)
语句;
说明:
(1)for是关键字;()括起来的是控制部分,三个表达式可以为任何表达式;“语句”是循环体,可以是任何单个语句(包括复合语句);
(2)for语句的流程如下图所示:
表达式1用于给循环变量赋初值,注意:
表达式1仅在进入for语句时执行一次;表达式2是循环条件,同while语句一样,先计算并测试表达式2的值,因此for语句的循环体有可能一次也不执行;表达式3用于修改循环变量的值,它在每次执行完循环体中的语句之后,都要被执行一次。
例如
1for(i:
=1;i<4;i++)
printf(“i=%ds=%d\n”,i,2*i);
执行时输出:
i=1s=2
i=2s=4
i=3s=6
2for(a=10,b=5;a<=b;a++)
printf(“a=%d,b=%d\n”,a,b);
执行时无输出。
3for(x=1;x=100;x++)
执行时死循环,输出无穷多个x=100.
4sum=0;
for(i=1;i<=n;i++)
sum=sum+i;
可以简化为
for(sum=0,i=1;i<=n;i++)
sum+=i;
进一步简化
for(sum=0,i=1;i<=n;sum+=i++);
注意:
⑴表达式1(e1)、表达式2(e2)和表达式3(e3)可以全部(或部分)地缺省,无论缺省哪一个表达式,分号均不能省;
⑵缺省e1和e3时,for语句(for(;e2;)等价于一个while语句(while(e2));
⑶缺省e2时的for语句(for(e1;;e3))和三个表达式都缺省的for语句(for(;;))都是无限循环,被省略的e2缺省值为1(永真),e1和e3没有缺省值。
2.程序举例
例10.输入一批整数,以0结束,输出其中的最大值。
分析:
从若干数中求最大值,最简单的方法式是;将所有的数进行两两比较,留下较大数用max保存,当所有的数都比较完后,max存放的就是最大数。
#include
voidmain(void)
{
intx,max;
printf(“inputnumbers,lastoneis0:
\n”);
scanf(“%d”,&x);
max=x;
for(;x;)
{
if(maxscanf(“%d”,&x);
}
printf(“max=%d\n”,max);
}
例11求n!
,n从终端输入
分析:
n=1*2*3*…*n,考虑n较大时,n!
可能溢出,应将结果变量说明为long或double.
#include“stdio.h”
voidmain(void)
{intn,i;
longfac;
printf(“inputn:
\n”);
scanf(“%d”,&n);
fac=1;
for(i=1;i<=n;fac*=i++);
printf(“%d!
=%ld\n”,n,fac);
}
注:
累乘过程开始之前,累乘器变量一定要置初值1,而不能置为0。
例12.输入一串字符,将其转换为一个十进制整数。
即模拟scanf(“%d”,&i)所实现的功能。
分析:
当用scanf(“%d”,&i)i为int型,从终端输入一个整数时,实际上键入的是组成该整数各位数字的一个字符串,scanf函数将每个字符码转换成字符的一位整数,并按相应的数字位拼成一个十进制整数,最后赋值给i.
如输入123,实际是字符’1’,’2’,’3’,转换方法是设输入一位字符是c,对应的整数位d=c-‘0’,如3=’3’-’0’=51-48
123=(‘1’-‘0’)*102+(‘2’-‘0’)*101+(‘3’-‘0’)*100
=(((‘1’-‘0’)*10+’2’-‘0’)*10)+’3’-‘0’
为了用循环结构实现拼数,可将上述转换过程简化为下面的转换公式:
result=result*10+c-‘0’
算法:
(1)跳过前导空白字符:
重复读字符,直到读入的字符是非空白字符为止。
(2)处理正负号:
检查第一个非空白字符是否为’-‘,如果是,将符号sign置为-1,否则置为1。
(3)跳过符号位,读入下一字符。
(4)拼数
(5)用符号乘result,得到最终结果。
#include“stdio.h”
voidmain(void)
{intc,sign,result;
printf(“inputastring[digits]:
\n”);
for(c=getchar();c==’\v’||c==’‘||c==’\n’||c==’\t’||c==’\r’c==’\f’;c=getchar());
sign=(c==’-‘)?
-1:
1;
if(c==’+’||c==’-‘)c=getchar();
for(result=0;c>=’0’&&c<=’9’;c=getchar())
result=10*result+c-‘0’;
result*=sign;
printf(“result=%d\n”,result);
}
使用标准库函数可简化上述程序,方法是:
使用isdigit(c)和isspace(c)。
相应的头文件为“ctype.h”。
isdigit(c)测试字符c是否是一个数字,如果c是数字,则函数返回值为非0,否则返回值为0。
等价于:
c>=’0&&c<=’9’
isspace(c)测试c是否空白字符,如果果c是空白字符,则函数返回值为非0,否则返