第一篇:全国计算机等级考试二级C语言题型总结(二)——选择循环结构程序设计部分
C语言第二部分上机题型总结
一、选择结构部分;
1、if结构题型总结(案例1)企业发放的奖金根据利润提成。利润(I)低于或等于10万元时,奖金可提10%;利润高
于10万元,低于20万元时,低于10万元的部分按10%提成,高于10万元的部分,可可提
成7.5%;20万到40万之间时,高于20万元的部分,可提成5%;40万到60万之间时高于
40万元的部分,可提成3%;60万到100万之间时,高于60万元的部分,可提成1.5%,高于
100万元时,超过100万元的部分按1%提成,从键盘输入当月利润I,求应发放奖金总数?
(习题1)
题目:输入一行字符,分别统计出其中英文字母、空格、数字和其它字符的个数。
2、switch结构(案例2)
题目:输入某年某月某日,判断这一天是这一年的第几天?
(习题2)要求从键盘输入一组字符,对该组字符中的数字0-9字符个数分别进行统计,其他字符共同统计,统计完成后输出各种字符的个数。(结合数组完成)
二、循环结构
1、for循环(案例3)
题目:一个整数,它加上100后是一个完全平方数,再加上168又是一个完全平方数,请问该数是多少? 1.程序分析:在10万以内判断,先将该数加上100后再开方,再将该数加上268后再开方,如果开方后的结果满足如下条件,即是结果。请看具体分析:
(习题3)按照指定的格式输出9*9乘法表。
* * * * * * * * * *
2.while循环
*
* *
* * * * * * *
*
* *
* * * * * * * * * * * *(案例4)请编写一个函数fun,它的功能是:根据以下公式求PI的值(要求满足精度0.0005,即某项小于0.0005时停止迭代):
PI/2 = 1 + 1/3 +(1*2)/(3*5)+(1*2*3)/(3*5*7)+(1*2*3*4)/(3*5*7*9)+ …… +(1*2*3*……*n)/(3*5*7*……(2*n+1))
(练习4)题目:将一个正整数分解质因数。例如:输入90,打印出90=2*3*3*5。
(习题5)题目:有一分数序列:2/1,3/2,5/3,8/5,13/8,21/13...求出这个数列的前20项之和。
(习题6)对数组的10个数进行排序
课后习题
题目:打印出所有的“水仙花数”,所谓“水仙花数”是指一个三位数,其各位数字立方和等于该数
本身。例如:153是一个“水仙花数”,因为153=1的三次方+5的三次方+3的三次方。
编写函数fun,它的功能是:利用以下所示的简单迭代方法求方程cos(x)-x=0的一个实根。
X(n+1)=cos(X(n))
迭代步骤如下:
(1)取x(1)初值为0.0;
(2)x(0)=x(1),把x(1)的值赋给x(0);
(3)x(1)=cos(x(0)),求出一个新的x(1);
(4)若x(0)-x(1)的绝对值小于0.000001,则执行步骤(5),否则执行步骤(2);
(5)所求x(1)就是方程cos(x)-x=0的一个实根,作为函数值返回。
(案例1)
#include“stdio.h” main(){
} long int i;int bonus1,bonus2,bonus4,bonus6,bonus10,bonus;scanf(“%ld”,&i);bonus1=100000*0.1;bonus2=bonus1+100000*0.75;bonus4=bonus2+200000*0.5;bonus6=bonus4+200000*0.3;bonus10=bonus6+400000*0.15;if(i<=100000)
bonus=i*0.1;bonus=bonus1+(i-100000)*0.075;bonus=bonus2+(i-200000)*0.05;bonus=bonus4+(i-400000)*0.03;bonus=bonus6+(i-600000)*0.015;bonus=bonus10+(i-1000000)*0.01;else if(i<=200000)else if(i<=400000)else if(i<=600000)else if(i<=1000000)else printf(“bonus=%d”,bonus);
案例2 main(){
int day,month,year,sum,leap;printf(“nplease input year,month,dayn”);scanf(“%d,%d,%d”,&year,&month,&day);switch(month)/*先计算某月以前月份的总天数*/ { case 1:sum=0;break;case 2:sum=31;break;case 3:sum=59;break;case 4:sum=90;break;case 5:sum=120;break;case 6:sum=151;break;case 7:sum=181;break;case 8:sum=212;break;case 9:sum=243;break;
} case 10:sum=273;break;case 11:sum=304;break;case 12:sum=334;break;default:printf(“data error”);break;} sum=sum+day;/*再加上某天的天数*/
if(year%400==0||(year%4==0&&year%100!=0))/*判断是不是闰年*/
leap=1;leap=0;sum++;else if(leap==1&&month>2)/*如果是闰年且月份大于2,总天数应该加一天*/ printf(“It is the %dth day.”,sum);
案例3 #include “math.h” main(){ long int i,x,y,z;for(i=1;i<100000;i++)
{ x=sqrt(i+100);
/*x为加上100后开方后的结果*/
y=sqrt(i+268);
/*y为再加上168后开方后的结果*/
if(x*x==i+100&&y*y==i+268)/*如果一个数的平方根的平方等于该数,这说明此数是完全平方数*/
printf(“n%ldn”,i);
} }
(案例4)
#include
{ double x;int i;
printf(“eps=%lf, PI=%lfn”, x, fun(x));
} } 习题4 程序分析:对n进行分解质因数,应先找到一个最小的质数k,然后按下述步骤完成:
(1)如果这个质数恰等于n,则说明分解质因数的过程已经结束,打印出即可。
(2)如果n<>k,但n能被k整除,则应打印出k的值,并用n除以k的商,作为新的正整数你n,重复执行第一步。
(3)如果n不能被k整除,则用k+1作为k的值,重复执行第一步。2.程序源代码:
/* zheng int is divided yinshu*/ main(){ int n,i;printf(“nplease input a number:n”);scanf(“%d”,&n);printf(“%d=”,n);for(i=2;i<=n;i++)
{
while(n!=i)
{
if(n%i==0)
{ printf(“%d*”,i);
n=n/i;
}
else
break;
} } printf(“%d”,n);}(习题5)main(){ int n,t,number=20;float a=2,b=1,s=0;for(n=1;n<=number;n++)
{
s=s+a/b;
t=a;a=a+b;b=t;
} printf(“sum is %9.6fn”,s);}
(课后习题6)
1.程序分析:可以利用选择法,即从后9个比较过程中,选择一个最小的与第一个元素交换,下次类推,即用第二个元素与后8个进行比较,并进行交换。
2.程序源代码: #define N 10 main(){int i,j,min,tem,a[N];/*input data*/ printf(“please input ten num:n”);for(i=0;i 《全国计算机等级考试二级教程——C语言程序设计》 课后题及参考答案 第一章 程序设计基本概念 1.1 在TRUBO C环境中用RUN命令运行一个C程序时,所运行的程序的后缀是______。答案:.exe 1.2 C语言源程序文件的后缀是_____,经过编译后,生成文件的后缀是_____,经过连接后,生成文件的后缀是_____。 答案:.c.obj.exe 1.3 结构化程序由_____、_____、_____三种基本结构组成。答案:顺序、选择、循环 第二章 C程序设计的初步知识 一、选择题 2.1 以下选项中正确的整型常量是 A)12.B)-20 C)1,000 D)4 5 6 答案:B 2.2 以下选项中正确的实型常量是 A)0 B)3.1415 C)0.329×10(2)(10的2次方) D).871 答案:D 2.3 以下选项中不正确的实型常量是 A)2.607E-1 B)0.8103e 2 C)-77.77 D)456e-2 答案:B 2.4 以下选项中不合法的用户标识符是 A)abc.c B)file C)Main D)PRINTF 答案:A 2.5 以下选项中不合法的用户标识符是 A)_123 B)printf C)A$ D)Dim 答案:C 2.6 C语言中运算对象必需是整型的运算符是 A)% B)/ C)! D)** 答案:A 2.7 可在C程序中用作用户标识符的一组标识符是 A)void define WORD B)as_b3 _123 If C)For -abc case D)2c DO SIG 答案:B 2.8 若变量已正确定义并赋值,符合C语言语法的表达式是 A)a=a+7; B)a=7+b+c,a++ C)int(12.3%4) D)a=a+7=c+b 答案:B 2.9 以下叙述中正确的是 A)a是实型变量,C允许进行以下赋值a=10,因此可以这样说:实型变量中允许存放整型值。 B)在赋值表达式中,赋值号右边既可以是变量也可以是任意表达式。 C)执行表达式a=b后,在内存中a和b存储单元中的原有值都将被改变,a的值已由原值改变为b的值,b的值由原值变为0。 D)已有a=3,b=5。当执行了表达式a=b,b=a之后,已使a中的值为5,b中的值为3。 答案:B 2.10 以下叙述中正确的是 A)在C程序中无论是整数还是实数,只要在允许的范围内都能准确无误的表示。 B)C程序由主函数组成。 C)C程序由函数组成。 D)C程序由函数和过程组成。 答案:C 2.11 TURBO C中int类型变量所占字节数是 A)1 B)2 C)3 D)4 答案:B 2.12 不合法的八进制数是 A)0 B)028 C)077 D)01 答案:B 2.13 不合法的十六进制数是 A)oxff B)0Xabc C)0x11 D)0x19 答案:A 二、填空题 2.14 若k为int整型变量且赋值11。请写出运算k++后表达式的值A)_____和变量的值B)_____。 答案: 11、12 2.15 若x为double型变量,请写出运算x=3.2,++x后表达式的值A)_____和变量的值B)_____。 答案:4.2、4.2 2.16 函数体由符号____开始,用符号____结束。函数体的前面是____部分,其后是____部分。 答案:{、}、定义、执行 2.17 C语言中的标识符可分为____、____、和预定义标识符三类。 答案:关键字、用户标识符 2.18 在C语言程序中,用关键字____定义基本整型量,用关键字____定义单精度实型变量,用关键字___定义双精度实型变量。 答案:int、float、double 2.19 把a1、a2定义成单精度实型变量,并赋初值1的定义语句是____。 答案:float a1=1.0,a2=1.0; 2.20 C程序中定义的变量,代表内存中的一个____。 答案:存储单元 2.21 表达式3.5+1/2的计算结果是____。 答案:3.5 2.22 对以下数学式,写出三个等价的C语言表达式____、____、____。 a×b —— c 答案:a*b/c、a/c*b、b/c*a 2.23 表达式s=10应当读做“____”。 答案:将10赋给变量s 2.24 计算机中内存储器的最小存储单位称____,其中能容纳的数是____。 答案:位、0或1 2.25 通常一个字节包含____个二进制位。在一个字节中能存放的最大(十进制)整数是____,它的二进制数的形式是____;最小(十进制)整数是____,它的二进制数的形式是____。 答案:8、255、1111 1111、-128、1000 0000 2.26 当计算机用两个字节存放一个整数时,其中能存放的最大(十进制)整数是____、最小(十进制)整数是____,它的二进制数的形式是____。 答案:65535、-32768、1000 0000 0000 0000 2.27 在C语言中整数可用____进制数、____进制数和____进制数三种数制表示。 答案:十、八、十六 三、上机改错题 2.24 【分析与解答】 第1行的错误: (1)include是一个程序行,因此在此行的最后不应当有分号(;)。 (2)include程序行中后面的stdio.h是一个文件名,按规定,文件名应当放在一对双引号(″ ″)内,或放在一对尖括号(< >)内。 第2行的错误: (1)main()是主函数的起始行,不是语句,因此最后不应当有分号(;)。 (2)在同一行上的/ * main function * / 显然是注释;C语言规定:注释由/*开头,由*/结束,但在*号和/之间不得插入任何空格,而在此处“/ *”和“/ *”之间存在空格,因此,/ * main function * /的写法式是错误的,而应写成:/* main function */。 第3行的错误: (1)在主函数的起始行main()的后面是函数体,函数体由左花括号({)开始。但在函数体的第一行:float的前面缺少了左花括号({)。 (2)在同一行上的/* /*r is radius*/, /* s is area of circular*/ */ 显然是注释;C语言规定:注释由/*开头,由*/结束,并且开头的/*将去找最近的*/去配对,因此在/* /*r is radius*/中,第一个/*与最后的那个*/配上了对,结果紧跟在后面的那个逗号(,)落在了注释的外面,而构成了一个多余符号,为此,在编译时将报告“语法错”。 第6行的错误: (1)printf(″%f \[KG-*3]n″,s)应当是一条输出语句,但在最后缺少了一个分号。 (2)printf(″%f \[KG-*3]n″,s);是程序的最后一条语句,程序应当结束;但缺少了程序体结束所需的右花括号(});此右花括号可以放在printf(″%f \[KG-*3]n″,s);的后面,也可以放在printf(″%f \[KG-*3]n″,s);的下一行上。 2.25 【分析与解答】 第1行的错误:在include行中的文件名应该是stdio.h,而不是stdio.a。 第2行的错误:在main的后面缺少一对圆括号。 第4行的错误:在c=40的后面缺少分号。 第6行的错误:在printf(″%f \〖KG-*3〗n″,v)的后面缺少分号。 第三章、顺序结构 一、选择题 3.1 若a、b、c、d都是int类型变量且初值为0,以下选项中不正确的赋值语句是 A)a=b=c=100; B)d++; C)c+b; D)d=(c=22)-(b++); 答案:C 3.2 以下选项中不是C语句的是 A){int i;i++;printf(“%d”, i);} B); C)a=5,c=10 D){;} 答案:C 3.3 以下合法的C语言赋值语句是 A)A=B=58 B)k=int(a+b); C)a=58,b=58 D)--i; 答案:D 3.4 以下程序的输出结果是 A)0 B)1 C)3 D)不确定的值 main() { int x=10,y=3; printf(“%d”, y=x/y); } 答案:C 3.5 若变量已正确说明为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); 答案:D 3.6 若变量已正确说明为float类型,要通过以下赋值语句给a赋予 10、b赋予 22、c赋予33,以下不正确的输入形式是 A)10 B)10.0,22.0,33.0 C)10.0 D)10 22 scanf(“%f %f %f”, &a, &b, &c); 答案:B 3.7 若变量以正确定义,要将a和b中的数进行交换,下面不正确的语句组是 A)a=a+b,b=a-b,a=a-b; B)t=a,a=b,b=t; C)a=t;t=b;b=a; D)t=b;b=a;a=t; 答案:C 3.8 若变量已正确定义,以下程序段的输出结果是 A)输出格式说明与输出项不匹配,输出无定值 B)5.17000 C)5.168000 D)5.169000 x=5.16894; printf(“%f”,(int)(x*1000+0.5)/(float)1000); 答案:D 3.9 若有以下程序段,c3中的值是 A)0 B)1/2 C)0.5 D)1 int c1=1,c2=2,c3; c3=c1/c2; 答案:A 3.10 若有以下程序段,其输出结果是 A)0,0,-10 B)0,0,5 C)-10,3,-10 D)3,3,-10 int a=0,b=0,c=0; c=(a-=a-5),(a=b,b+3); printf(“%d,%d,%d”,a,b,c); 答案:B 3.11 当运行以下程序时,在键盘上从第一列开始输入9876543210 A)a=98,b=765,c=4321 B)a=10,b=432,c=8765 C)a=98,b=765.000000,c=4321.000000 D)a=98,b=765,c=4321.0 main(){ int a;float b,c; scanf(“%2d%3f%4f”,&a,&b,&c); printf(“a=%d,b=%f,c=%f”,a,b,c);} 答案:C 3.12 以下程序的输出结果是 A)a=%2,b=%5 B)a=2,b=5 C)a=%%d,b=%%d D)a=%d,b=%d main(){ int a=2,b=5; printf(“a=%%d,b=%%d”,a,b);} 答案:D 3.13 若int类型占两个字节,则以下程序段的输出是 A)-1,-1 B)-1,32767 C)-1,32768 D)-1,65535 int a=-1; printf(“%d,%u”,a,a); 答案:D 3.14 以下程序段的输出是 A)*496 * B)* 496* C)*000496* D)输出格式符不合法 int x=496; printf(“*%-06d*”,x); 答案:A 3.15 以下程序段的输出是 A)|3.1415| B)| 3.0| C)| 3| D)| 3.| float a=3.1415; printf(“|%6.0f|”,a); 答案:C 3.16 以下程序段的输出是 A)|2345.67800| B)|12345.6780| C)|12345.67800| D)|12345.678| printf(“|%10.5f|”,12345.678); 答案:C 3.17 以下程序段的输出是 A)*0000057.66* B)* 57.66* C)*0000057.67* D)* 57.67* float a=57.666; printf(“*%010.2f*”,a); 答案:C 3.18 若从终端输入以下数据,要给变量C赋以283.19,则正确的输入语句是 A)scanf(“%f”,c); B)scanf(“%8.4f”,&c); C)scanf(“%6.2f”,&c); D)scanf(“%8”,&c); 283.1900 答案:由于印刷错误,本题没有正确答案。改正意见: 把选项A改为:scanf(“%f”,&c);或者把选项D改为:scanf(“%8f”,&c);则可分别选择A或者D为正确答案。 3.19 若变量已正确说明,要求用以下语句给a赋予3.12、给b赋予9.0,则正确的输入形式是(□代表空格) A)3.12□□9.0 B)a=□□3.12b=□□□9 C)a=3.12,b=9 D)a=3.12□□,b=9□□□□ scanf(“a=%f,b=%f”,&a,&b); 答案:C 3.20 以下程序的输出结果是 A)9 8 B)8 9 C)6 6 D)以上三个都不对 #include “math.h” main(){ double a=-3.0, b=2; printf(“%3.0f %3.0f”,pow(b,fabs(a)),pow(fabs(a),b));} 答案:B 二、填空题 3.21 若有以下定义,请写出以下程序段中输出语句执行后的输出结果。(1)____(2)____(3)____ int i=-200,j=2500; printf(“(1)%d %d”,i,j); printf(“(2)i=%d, j=%d”,i,j); printf(“(3)i=%d j=%d”,i,j); 答案: -200 2500 i=-200, j=2500 i=-200 j=2500 3.22 变量i、j、k已定义为int类型并有初值0,用以下语句进行输入时 scanf(“%d”,&i);scanf(“%d”,&j);scanf(“%d”,&k);当执行第一个输入语句,从键盘输入: 12.3 则变量i、j、k的值分别是____、____、____。 答案:12、0、0 3.23 复合语句在语法上被认为是____。空语句的形式是____。 答案:一条语句、; 3.24 C语句的最后用____结束。 答案:; 3.25 以下程序段,要求通过scanf语句给变量赋值,然后输出变量的值。写出运行时给k输入100,给a输入25.81,给x输入1.89234时的三种可能的输入形式____、_____、____。 int k;float a;double x; scanf(“%d%f%lf”,&k,&a,&x); printf(“k=%d,a=%f,x=%f”,k,a,x); 答案: (1)100 25.81 1.89234 (2)100 25.81 (3)100 int x=0177; printf(“x=%3d,x=%6d,x=$%6o,x=%6x,x=%6u”,x,x,x,x,x); 答案:x=127,x= 127,x= 177,x= 7f,x= 127 3.27 以下程序段的输出结果是____。 int x=0177; printf(“x=%-3d,x=%-6d,x=$%-06d,x=$%06d,x=%%06d”,x,x,x,x,x); 答案: 27、x=127,x=127,x=$127,x=$000127,x=%06d 3.28 以下程序段的输出结果是____。 double a=513.789215; printf(“a=%8.6f,a=%8.2f,a=%14.8f,a=%14.8lf”,a,a,a,a);答案:a=513.789215,a= 513.79,a= 513.78921500,a= 513.78921500 三、编程题和改错题 3.16 【分析与解答】 (1)主函数名main后应有一对圆括号。(2)变量定义语句中,v的前面缺逗号。 (3)第三行的printf语句用以提示输入,但是原样输出的字符串没有用双引号括起来;另外,从输入的形式看,输入的数据紧跟在提示之后,因此,printf格式串中最后不应该有换行符——\n。 (4)因为输入项a、b、c从定义和计算结果来看都是double类型,因此,第四行scanf语句格式串中的格式说明不应当用%d而应当用%lf;且每一个变量之前应该加地址运算符&。 (5)第七行的printf语句中应当把%d都改成%lf或%f;按输出要求在格式串中应添加相应的原样输出的字符;因为下一个printf的输出从新的一行开始,因此在本输出语句的格式串的最后应当加换行符——\n。 (6)第八行的printf语句中应当把格式串整理合并放在输出项的前面,输出项放在后面,%d都改成%lf或%f;中间的\n删去。 (7)请读者自己写出修改后的程序,并上机调试。 3.17【分析与解答】 (1)分析:可用算术式560÷60把分钟换算成小时和分钟,商数就是小时数,余数就是分钟数。 (2)确定变量的名字和定义变量的类型:在程序中把小时数放在变量h中,把分钟数放在变量m中。这两个变量的类型可以是整型(本题中采用整型),也可以是实型。 (3)确定所用算法:求〖SX()560〖〗60〖SX〗〗的商数,在C语言中可以用整除的算法,语句是h=560/60。求余数可用求余运算符 %:560%60,其值放入变量m中的语句是:m=560%60。(4)设计输出格式。若输出的形式定为:小时:分钟,则按此形式设计输出语句。(5)把以上内容放在主函数的一对花括号中。(6)编写程序如下: main() { int h, m; h=560/60; m=560%60; printf(″The result: %3d : %3d\n″, h,m); } 运行结果是: The result: : 20 3.18 【分析与解答】 (1)确定变量的名字和定义变量的类型。若用a存放1500,用b存放350;用q存放商数,用r存放余数,所有变量应定义成int类型。 (2)设计输入语句从终端输入1500和350;在输入语句之前,应当设计一个输出语句,用以提示输入。(3)可用整除求商数,结果放在变量q中。可用求余运算符%求两数之余数,结果放在变量r中。(4)设计输出语句。输出a、b、q、r。 (5)把以上内容放在主函数的一对花括号中。 本题的程序与3.30相似,请读者参考上题并根据本题的解释自己编程,并上机调试。 3.19 【分析与解答】 (1)定义4个双精度变量a、b、c和ave,变量a、b、c分别存放读入的3个双精度数,ave存放它们的平均值。 (2)设计输入语句,以及在此之前用于提示输入的(printf)语句。(3)设计求平均值的算法,把所求得的平均值放入变量ave中。 (4)设计把变量ave中的数,从小数点后第二位数进行四舍五入的算法。现举例说明:若ave中的数为123.4644,为了保留此值小数点后一位,可用表达式:(int)(123.4644*10)/10.0;依次推算,为了保留此值小数点后二位,可用表达式:(int)(123.4644*100)/100.0;其他依此类推。 (5)若要求对小数点后第二位数进行四舍五入,则可对原数加0.05后再进行以上运算。如要求保留123.4644小数点后一位且对第二位数进行四舍五入,可用表达式:(int)((123.467+0.05)*10)/10.0。注意:分母一定要用实数10.0而不能用整数10,否则就变成整除了;若要求保留123.4644小数点后两位且对第三位数进行四舍五入,可用表达式:(int)((123.467+0.005)*100)/100.0;其他依此类推。(6)设计输出语句。输出a、b、c和ave。(7)把以上内容放在主函数的一对花括号中。(8)编写程序如下: main() { double a,b,c,ave; printf(″Enter a ,b ,c : ″); scanf(″%lf%lf%lf″, &a, &b, &c); ave=(a+b+c)/3; printf(″ave=%f\n″, ave); /*用以比较四舍五入前后的数据*/ ave=(int)((ave+0.05)*10)/10.0; printf(″a=%f, b=%f, c=%f, ave=%f\n″, a,b,c,ave); } 3.20 【分析与解答】 (1)关于对变量中的数进行交换的算法请参考3.7题中的解释和《教程》中有关的例题。 (2)定义4个整型变量a、b、c和t,变量a、b、c分别存放读入的3个整数,t用作临时存储单元。(3)设计输入语句,以及在此之前用于提示输入的(printf)语句。(4)输出a、b、c中的值,以便于比较。(5)交换的步骤如下: ① 把c中的值赋给t。 ② 把b中的值赋给c。 ③ 把a中的值赋给b。 ④ 把t中的值赋给a。 经过以上步骤,已按要求进行了交换。(6)输出a、b、c中的值。(7)编写程序如下: main() { int a, b, c, t; printf(″Enter a, b, c :\n″); scanf(″%d%d%d″,&a,&b,&c); printf(″(1)a=%d,b=%d,c=%d\n″,a,b ,c); t=c;c=b;b=a;a=t; printf(″(2)a=%d,b=%d,c=%d\n″,a,b,c); } 第四章、选择结构 一、选择题 4.1 下列运算符中优先级最高的运算符是 A)! B)% C)-= D)&& 答案:A 4.2 下列运算符中优先级最低的运算符是 A)|| B)!= C)<= D)+ 答案:A 4.3 为表示关系x≥y≥z,应使用的C语言表达式是 A)(x>=y)&&(y>=z) B)(x>=y)AND(y>=z) C)(x>=y>=z) D)(x>=y)&(y>=z) 答案:A 4.4 设a、b和c都是int型变量,且a=3,b=4,c=5;则以下的表达式中,值为0的表达式是 A)a&&b B)a<=b C)a||b+c&&b-c |1) 答案:D 4.5 以下程序的输出结果是 A)0 B)1 C)2 D)3 main() { int a=2,b=-1,c=2; if(a if(b<0)c=0; else c+=1; printf(“%d”,c); } D)!((a 答案:C 4.6 以下程序的输出结果是 A)1 B)2 C)3 D)4 main(){ int w=4,x=3,y=2,z=1; printf(“%d”,(w 答案:A 4.7 若执行以下程序时从键盘上输入3和4,则输出结果是 A)14 B)16 C)18 D)20 main(){ int a,b,s; scanf(“%d%d”,&a,&b); s=a; if(a s*=s; printf(“%d”,s);} 答案:B 4.8 下面的程序片段所表示的数学函数关系是 -1(x<0)A)y= 0(x=0) 1(x>0) 1(x<0)B)y=-1(x=0) 0(x>0) 0(x<0)C)y=-1(x=0) 1(x>0) -1(x<0)D)y= 1(x=0) 0(x>0) y=-1;if(x!=0)y=1; if(x>0)y=1;else y=0;答案:A 4.9 运行以下程序后,输出 A)**** B)&&&& C)####&&&& D)有语法错误不能通过编译 main(){ int k=-3; if(k<=0)printf(“****”) else printf(“&&&&”);} 答案:D 4.10 若a和b均是正整型变量,以下正确的switch语句是 A)switch(pow(a,2)+pow(b,2)) { case 1: case 3: y=a+b;break; case 0: case 5: y=a-b; } B)switch(a*a+b*b); { case 3: case 1: y=a+b;break; case 0: y=b-a;break; } C)switch a { default: x=a+b; case 10: y=a-b;break; case 11: x=a*d;break; } D)switch(a+b) { case10 : x=a+b;break; case11 : y=a-b;break; } 答案:没有正确答案。如果C选项改为: switch(a){ default: x=a+b; case 10: y=a-b;break; case 11: x=a*b;break;} 则答案可以选择C 二、填空题 4.11 C语言中用____表示逻辑值“真”,用____表示逻辑值“假”。 答案:非0、0 4.12 C语言中的关系运算符按优先级别是____、____、____、____。 答案:>、<、>=、<=、==、!= 4.13 C语言中的逻辑运算符按优先级别是____、____、____。 答案:!、&&、|| 4.14 C语言中的关系运算符和逻辑运算符的优先级别是____、____、____、____、____、____、____。 答案:!、<、>、==、!=、&&、|| 4.15 C语言中逻辑运算符____的优先级高于算术运算符。 答案:! 4.16 将下列数学式改写成C语言的关系表达式或逻辑表达式A)____B)____。 A)a=b或a B)|x|>4 答案:A)a==b||a main(){ int a=100; if(a>100)printf(“%d”,a>100); else printf(“%d”,a<=100);} 答案:1 4.18 请写出与以下表达式等价的表达式A)____B)____。A)!(x>0) B)!0 答案:A)x<=0 B)1 4.19 当a=1,b=2,c=3时,以下if语句执行后,a、b、c中的值分别为____、____、____。 if(a>c) b=a;a=c;c=b; 答案:3、2、2 4.20 若变量已正确定义,以下语句段的输出结果是____。 x=0;y=2;z=3; switch(x) { case 0: switch(y==2) { case 1: printf(“*”);break; case 2: printf(“%”);break; } case 1: switch(z) { case 1: printf(“$”); case 2: printf(“*”);break; default : printf(“#”); } } 答案:*# 三、编程题 4.21 【分析与解答】 相关内容请参考《教程》4.2节和4.4节。(1)改写如下: switch(a/10) { default : m=5;break; case 0 : case 1 : case 2 : m=1;break; case 3 : m=2;break; case 4 : m=3;break; case 5 : m=4;break; }; (2)本题中对a的判断条件有一定的规律可寻;关键是,在switch语句后的表达式中利用了a/10,从而简化了case标号。 4.22 【分析与解答】 编写本题的程序,首先要解决如何计算学生当前的年龄(设存放实足年龄的变量是age)。(1)如果当前的月份大于生日的月份,则学生的实足年龄age=y1-y0。 (2)如果当前的月份等于生日的月份,就要看日数,当前的日数大于或等于生日的日数,则学生的实足年龄age=y1-y0。 (3)如果不满足以上的条件,就可断定当前的日期没有超过生日日期,就是说学生的年龄应当是age=y1-y0-1。 以上3条,用C语言可以描述如下: if((m1>m0)[JB>1|][JB>1|](m1==m0&&d1>=d0))age=y1-y0; else age=y1-y0-1; 读者可以参考以上语句写出程序,也可以根据分析写出与此形式不同的语句和程序。 4.23【分析与解答】 (1)若输入的整数a是奇数,输出 dd number,是偶数输出:even number。 (2)若一个a是偶数,它就能被2除尽,即a%2==0,输出even number;若是奇数,它就不能被2除尽,即a%2!〖KG-*2〗=0,输出odd number。 读者可以参考以上给出的算法,写出相应的C语句,并编写出完整的程序。 4.24 【分析与解答】 本题的主要算法是从3个数中找出最大的那个数。假定始终把最大的数放在变量max中。(1)假定a中的数最大,把a赋给max。 (2)用b去和max比较,若b大于max,则把b赋给max;若不大于max,则什么也不做。(3)用c去和max比较,若c大于max,则把c赋给max;若不大于max,则什么也不做。(4)经过以上操作,max中已放入了a、b、c三个数中的最大数,输出max即可。 读者可以参考以上给出的算法,写出相应的C语句,并编写出完整的程序。 4.25 【分析与解答】 (1)本题已给出了非常明确的条件,只要写出正确的条件判断语句就可基本完成程序的编写。 (2)由给出的函数可知,只有x的值在规定的范围内时,才求出y的值,因此程序应当对输入的x进行判断,若超过范围就不求y的值。 (3)现以使用if[CD#*2]else语句为例写出程序供参考。 main() { int x,y;printf(″Enter x : ″);scanf(″%d″, &x); if(x>-5&&x<10) { if(x==0)y=x-1; else if(x<10 && x>0)y=x+1; else if(x<0 && x>-5)y=x; printf(″x=%d y=%d\n″, x,y); } printf(″***END***\n\n″); } 第五章、循环结构 一、选择题 5.1 以下程序段的输出结果是 A)9 B)1 C)11 int k,j,s; for(k=2;k<6;k++,k++) { s=1; for(j=k;j<6;j++)s+=j; } printf(“%d”, s); 答案:D 5.2 以下程序段的输出结果是 A)12 B)15 C)20 int i,j,m=0; for(i=1;i<=15;i+=4) for(j=3;j<=19;j+=4)m++; printf(“%d”, m); 答案:C 5.3 以下程序段的输出结果是 A)10 B)9 C)10 D)9 D)10 D)25 int n=10; while(n>7) { n--; printf(“%d”, n); } 答案:B 5.4 以下程序段的输出结果是 A)1 B)3 0 C)1-2 int x=3; do { printf(“%3d”,x-=2);} while(!(--x)); 答案:C 5.5 以下程序段的输出结果是 A)15 B)14 C)不确定 main() { int i,sum; for(i=1;i<6;i++)sum+=sum; printf(“%d”,sum); } 答案:C 5.6 以下程序段的输出结果是 A)741 B)852 C)963 main() { int y=10; for(;y>0;y--) if(y%3==0) { printf(“%d”,--y);continue; } 答案:B 5.7 若x是int型变量,以下程序段的输出结果是 A)**3 ##4 **5 B)##3 **4 ##5 C)##3 **4##5 D)**3##4 **5 for(x=3;x<6;x++) printf((x%2)?(“**%d”):(##%d“),x); D)死循环 D)0 D)875421 } 答案:D 5.8 以下程序的输出结果是 A)*#*#*#$ B)#*#*#*$ C)*#*#$ D)#*#*$ main(){ int i; for(i=1;i<=5;i++) { if(i%2)printf(”*“); else contionue; printf(”#“); } printf(”$“);} 答案:A 5.9 以下叙述正确的是 A)do_while语句构成的循环不能用其它语句构成的循环来代替。 B)do_while语句构成的循环只能用break语句退出。 C)用do_while语句构成循环时,只有在while后的表达式为非零时结束循环。 D)用do_while语句构成循环时,只有在while后的表达式为零时结束循环。 答案:D 5.10 以下程序的输出结果是 A)39 81 B)42 84 C)26 68 D)28 70 main(){ int x,i; for(i=1;i<=100;i++) { x=i; if(++x%2==0) if(++x%3==0) if(++x%7==0) printf(”%d “, x); } printf(”“);} 答案:D 二、填空题 5.11 当执行以下程序段后,i的值是____、j的值是____、k的值是____。 int a,b,c,d,i,j,k;a=10;b=c=d=5;i=j=k=0;for(;a>b;++b)i++;while(a>++c)j++;do k++;while(a>d++); 答案:5、4、6 5.12 以下程序段的输出结果是____。 int k,n,m;n=10;m=1;k=1;while(k<=n)m*=2;printf(”%d“,m); 答案:死循环 5.13 以下程序的输出结果是____。 main(){ int x=2; while(x--); printf(”%d“,x);} 答案:-1 5.14 以下程序段的输出结果是____。 int i=0,sum=1; do { sum+=i++;}while(i<5); printf(”%d“,sum); 答案:11 5.15 有以下程序段: s=1.0; for(k=1;k<=n;k++)s=s+1.0/(k*(k+1)); printf(”%f“,s);请填空,使下面的程序段的功能完全与之等同。 s=0.0; ____; k=0; do { s=s+d; ____; d=1.0/(k*(k+1)); } while(____); printf(”%f“,s); 答案:d=1.0、k++、k<=n 5.16 以下程序的功能是:从键盘上输入若干个学生的成绩,统计并输出最高成绩和最低成绩,当输入负数时结束输入。请填空。 main() { float x,amax,amin; scanf(”%f“,&x); amax=x;amin=x; while(____) { if(x>amax) amax=x; if(____) amin=x; scanf(”%f“,&x); } printf(”amax=%famin=%f“,amax,amin); } 答案:x>=0、x 三、编程题 5.17【分析与解答】 (1)本题的基本算法是求累加值。累加项的值有规律的递增,每一项的绝对值比前一项增2,因此可以利用循环的控制变量的递增来得到累加项的绝对值。例如: for(i=1;i<=101;i+=2)„ (2)按所给的算式可以看到,累加项的符号是在交叉改变的,为此应当在循环体内设 置一个变量,使它的符号按此规律交叉改变,这可用:s=-s;来实现,s的初值为1;当s的值为1时,赋值后s中新的值为-1,当s的值为-1时,赋值后s中新的值为1。用s去乘累加项,将使累加项的符号也随之有规律地改变。(3)若累加和放在变量sum中,累加项放在变量t中,按照以上叙述,for循环体内的语句可以设计如下: s=-s;t=s*i;sum=sum+t;(4)sum的值是51。 (5)请读者自己对变量做出正确的定义并赋初值,设计输出语句,完善程序。 5.18 【分析与解答】 (1)本题的基本算法是求累加值。累加项的分子部分都是1;分母的值有规律的递增,依次为1!、2!、„、n!,即,若第i-1项的累加项为 t(i-1),则第i项的累加项是 t(i-1)*i,在程序中可用表达式:t=t/i(i从1变化到n)来表示。(2)根据以上分析,若用变量t来存放累加项,当i的值从1变化到n时,可用以下语句来实现累加: t=t/i;e+=t; (3)为了实现累加过程,以上语句应当放在循环内,循环控制变量从1变化到n。 (4)若用for循环,按题目要求已指定n的值是50。若用while循环,并没有指定n的值,但已指定了循环结束的条件,当t的值小于10-4结束循环。(5)现例示用while循环来求e值的部分程序: i=1;e=1.0;t=1.0; while(t>=1e-4) { t=t/i; e+=t; i++; } (6)请读者自己对变量做出正确的定义,设计输出语句,完善程序;也可以参考此程序段,按照自己的思路独立地完成程序。(7)e的值应当是:2.71828。 (8)根据以上分析,读者已不难用for循环来实现求e值的计算。 (9)注意:在完成此程序时,不要对分母中的阶乘值进行单独计算,因为17!的值已超过long类型的最大值,更无法求到50!。 5.19【分析与解答】 (1)从1880年至2000年的年数可用一个for循环来取得。 (2)对每一年,用以上指定的条件来进行判断,若满足条件即为闰年,进行输出。 (3)按输出的要求,需要设一个变量用于统计一行中输出的个数,若在一行上已连续输出了5个年数,就需输出一个换行符,使下一个输出项在新的一行上开始;若用变量n来做此统计,则当表达式n%5==0时就应输出一个换行符,同时使n重新置0值。 (4)若变量y代表年数,if语句的逻辑表达式可以写成如下: (y%4==0 && y%100!=0[JB>1|][JB>1|]y%400==0)(5)以下程序段供参考: for(y=1880;y<=2000;y++) if(y%4==0 && y%100![KG-*2]=0[JB>1|][JB>1|]y%400==0) { printf(″%d ″,y); n++; if(n%5==0) { printf(″\n″);n=0;} } (6)请读者自己对变量做出正确的定义并赋初值,完善程序;也可以参考此程序段,按照自己的思路独立地完成程序。从1880年至2000年有30个闰年。 5.20 【分析与解答】 (1)不难理解利用以下的for循环可以在一行上连续输出n个*号: for(i=1;i<=n;i++)printf(″*″); printf(″\n″); 若n的值是6,则连续输出6个*号。 (2)以上图形是在各行上输出数目不等的*号,只是*号的数目依次有规律地变化。在上半部分各行依次是1、3、5、7个,因此可以用以下的程序段来实现这样的输出: for(k=1;k<=7;k++,k++) { for(i=1;i<=k;i++)printf(″*″); printf(″\n″); } 在下半部依次是5、3、1个;因此可以用以下的程序段来实现这样的输出: for(k=5;k>=1;k--,k--) { for(i=1;i<=k;i++)printf(″*″); printf(″\n″); } 以上程序段从第一列起输出的结果如下: * *** ***** ******* ***** *** * 现在我们已完成了在每行输出指定数目的*号。 (3)输出结果与题目要求不同,它们的区别是:按题目每一行之前有不同的空格,而这里则是所有的行都在第一列上开始输出*号;所以接着就应当解决这一问题。(4)分析题目要求,每行第一个*号位置的缩进是有规律的,假定中间这一行第一个*号位置是在第一列,则可看出,第一至第三行的缩进分别是3、2、1个空格;而图形下半部的缩进数则刚好相反。这可在以上循环中添加输出连续空格的for循环来实现,对于上半部程序如下: b=3; for(k=1;k<=7;k++,k++) { for(j=1;j<=b;j++)printf(″ ″);b--; for(i=1;i<=k;i++)printf(″*″); printf(″\n″); } (5)请读者在理解以上给出的示例的基础上,自己添加下半部空格的输出。 第六章、字符型数据 一、选择题 6.1 C语言中的简单数据类型有 A)整型、实型、逻辑型 B)整型、实型、字符型 C)整型、字符型、逻辑型 D)整型、实型、逻辑型、字符型 答案:B 6.2 C语言中,字符(char)型数据在微机内存中的存储形式是 A)反码 B)补码 C)EBCDIC码 D)ASCII码 答案:D 6.3 设有语句char a=''72'';,则变量a A)包含1个字符 B)包含2个字符 C)包含3个字符 D)说明不合法 答案:A 6.4 C语言中不合法的字符常量是 A)'' xff'' B)''65'' C)''&'' D)'' 28'' 答案:本题A)和D)选项都是不合法的字符常量。若A)选项改为''ÿ'',则正确。6.5 C语言中不合法的字符串常量是 A)”121“ B)''y='' C)” “ D)”ABCDm“ 答案:B 6.6 判断char型变量c是否为大写字母的最简单且正确的表达式是 A)''A''<=c<=''Z'' B)(c>=''A'')&(c<=''Z'') C)(''A''<=c)AND(''Z''>=c) D)(c>=''A'')&&(c<=''Z'') 答案:D 6.7 以下程序的输出结果是 A)因输出格式不合法,无正确输出 B)65,90 C)A,Y D)65,89 main(){ char c1=''A'',c2=''Y''; printf(”%d,%d“,c1,c2);} 答案:D 6.8 以下程序段的输出结果是 A)A B)a C)Z D)z main(){ char x=''A''; x=(x>=''A''&&x<=''Z'')?(x+32):x; printf(”%c“,x);} 答案:B 6.9 以下程序的输出结果是 A)67,C B)B,C C)C,D D)不确定的值 main(){ char ch1,ch2; ch1=''A''+''5''-''3''; ch2=''A''+''5''-''3''; printf(”%d,%c“,ch1,ch2);} 答案:A 6.10 对以下程序,从第一列开始输入数据:2473 A)668977 B)668966 C)66778777 D)6688766 #include ”stdio.h“ main(){ int c; while((c=getchar())!='''') { switch(c-''2'') { case 0 : case 1 : putchar(c+4); case 2 : putchar(c+4);break; case 3 : putchar(c+3); default : putchar(c+2);break; } printf(”“); } } 答案:A 6.11 若变量已正确说明,要求用以下语句给c1赋予字符%、给c2赋予字符#、给a赋予2.0、给b赋予4.0,则正确的输入形式是(□代表空格) A)2.0□%□4.0□# B)2.0%4.0# C)2%□□4# D)2□%□4□ scanf(”%f%c%f%c“,&a,&c1,&b,&c2); ( 答案:B 二、填空题 6.12 EOF的十进制值是____。 答案:-1 6.13 C语言中,字符占内存____个字节。 答案:1 6.14 调用C语言对字符处理的库函数时,在#include命令行中应包括的头文件是____。 答案:string.h 6.15 若输入字符A,在以下while语句执行后ch的值是____。 while(ch=getchar()==''A''); 答案:1 6.16 若要通过以下语句给a、b、c、d分别输入字符A、B、C、D,给w、x、y、z分别输入10、20、30、40,正确的输入形式是____,请用 scanf(”%d%c%d%c%d%c%d%c“,&w,&a,&x,&b,&y,&c,&z,&d); 答案:10A20B30C40D 6.17 若有以下说明和输入语句,要求给c1、c2输入字符A和B,给a1、a2输入7.29和101.298,从键盘正确输入数据的形式是____。 char c1,c2; float a1,a2; scanf(”%f%f“,&a1,&a2); scanf(”%c%c“,&c1,&c2); 答案:7.29 char c1,c2; float a1,a2; scanf(”%c%f%c%f“,&c1,&a1,&c2,&a2); 答案:A7.29B101.298 6.19 若有以下说明和输入语句,要求给c1、c2、c3输入字符A、B和C,请写出各种从键盘正确输入数据的形式。 char c1,c2,c; scanf(”%4c“,&c1); scanf(”%4c“,&c2); scanf(”%4c“,&c3);答案:A□□□B□□□C□□□ 三、编程题 6.20【分析与解答】 (1)在进行字符输入时,即使一次输入了一行字符(最后用回车结束输入),字符也只能一个一个地读入。若ch已定义为char型变量,可以用以下的程序段来完成操作: ch=getchar(); while(ch![KG-*2]=′\n′) { „„ ch=getchar(); } 当读入的是一个回车符时,循环就结束。循环体内的“„„”符号表示需要在循环体内完成的其他操作。 (2)在循环内要求进行的操作之一是:输出每个字符以及与之对应的ASCII代码值。因此可用以下语句来实现。 printf(″%c : %d ″,ch,ch); (3)在循环内要求进行的另一个操作是:每行只能输出3对字符和与之对应的ASCII代码值。若n已定义为int型变量,则可用来作计数器;使n的初值为0,每输出一次,n的值增1,当n的值为3的整数倍时,额外输出一个换行符。例如: n++; if(n%3==0)putchar(′\n′); (4)把(2)和(3)中给出的语句放在循环体内,并按要求给出正确的定义和初值,就可完成题目所要求的操作。(5)也可以在while后的一对括号中来完成字符的读入,如while((ch=getchar())![KG-*2]=′\n′)。这时,循环内、外的“ch=getchar();”语句应当去掉。 6.21【分析与解答】 (1)一行字符的读入,请参照题6.20(1)和(5)中的解释。循环体内的“„„”符号表示需要在循环体内完成的其他操作。 ch=getchar(); while(ch![KG-*2]=′\n′) { „„ ch=getchar(); } (2)在本题中循环体内需要把读入的所有数字字符转换成一个整数。若用变量n来存放这个整数,为了保证有效的存放,应当把它定义成long类型。 (3)要把输入的一串数字字符转换成一个整数,首先需要判断当前读入的字符是否是数字字符,若不是则什么也不做;若是,则进行以下操作: ① 把当前读入的一个字符转换成一个一位整数,这可由语句“d=ch-′0′;”来实现,在这里d是一个整型变量; ② 把d中的一位数归并到n的低位中,这可用语句“n=n*10+d;”来实现。这里所述的操作可由以下语句来完成: if(ch>=′0′&&ch<=′9′){ d=ch-′0′;n=n*10+d;} if语句后一对括号中的判断表达式可以调用字符函数isdigit来实现: if(isdigit(ch)){ d=ch-′0′;n=n*10+d;} if子句的两个语句可以合并成:n=n*10+ch-′0′。(4)把(3)中的语句放入循环中: ch=getchar(); while(ch![KG-*2]=′\n′) { if(ch>=′0′&&ch<=′9′)n=n*10+ ch-′0′; ch=getchar(); } (5)请自己写出定义语句并赋初值。注意,最后输出n时,应当使用格式说明%ld,而不能使用%d。 6.22【分析与解答】 (1)行数的统计可通过统计输入的′\n′符的个数来完成。 (2)统计的过程应当放在一个while循环体中;判断循环是否进行的条件可以用:((ch=getchar())==EOF)。若用整型变量n作为计数器对′\n′符进行统计,只要读入的字符是′\n′,则n增1。如: while((ch=getchar())![KG-*2]=EOF) if(ch==′\n′)n++; (3)EOF是在stdio.h中预定义了的标识符,在TURBO C的环境下,键入Ctrl+Z(即按住键盘上的Ctrl键,同时按字母Z键)后,敲Enter键,即输入了EOF。 6.23【分析与解答】 (1)本题要求的操作同样可在while循环中完成: while((ch=getchar())!=′\n′) { „„ } (2)若用整型变量n作为计数器对小写字母进行统计,只要读入的字符是小写字母,则n增1。如: if(ch>=′a′ && ch<=′z′)n++;(3)在退出循环后,输出n的值。(4)请自己完善程序。 6.24【分析与解答】 (1)若图案的行数输入到变量L中。 (2)按要求L决定了图形的行数,因此可通过循环来实现L行的输出: for(i=1;i<=L;i++) { „„ } 循环体中的“„„”号,代表输出L行的操作。 (3)假定ch中存放了一个字符,我们知道,通过以下循环可以在一行上输出n个字符: for(j=1;j<=n;j++)putchar(ch); putchar(′\n′); 注意,在循环后putchar(′\n′);语句不可少,它用以换行。 (4)现在应当解决如何按要求给出每行输出的字符。由图分析,行数(或行号)为1时输出字符A,行数为2时输出字母B„„若输出的字母放在变量ch中,行号取决于外循环的控制变量i,则输出的字母和行号的关系可用表达式:ch=′A′+i-1来表示。当i为1时ch中被赋予字母A,当i为2时ch中被赋予了字母B,其他依此类推。因此,在此表达式后,利用(3)中的循环就解决了各行上输出的字母。(5)按要求每行输出的字母的个数不同,第二行输出3个字母,第三行输出5个字母,第四行输出7个字母„„(3)中for循环体的执行次数取决于n的值,也就是说n的值决定了每行输出字母的个数。其实,n的值与行号有着密切的关系:n=2*i-1,当i为1时n的值是 1、当i的2时n的值是 3、当i的3时n的值是 5、当i的4时n的值是7。因此在(3)中for循环之前可用此表达式求出n的值。(6)总结以上分析,我们可得到以下的程序段: for(i=1;i<=L;i++) { ch=′A′+i-1; n=2*i-1; for(j=1;j<=n;j++)putchar(ch); putchar(′\n′); } 若所用的变量都已正确定义,通过输入L的值为5,则程序段在第一列起有以下的输出结果: A BBB CCCCC DDDDDDD EEEEEEEEE 和题目的要求比较已趋接近,不同的是在每行没有适当的缩进。 (7)现在来解决每行的缩进问题。由题中给出的图形可知,若指定输出5行,第一行缩进5个空格,第二行则缩进4个空格,第三行则缩进3个空格,第四行则缩进2个空格,第五行则缩进1个空格。这同样可以由以下的for循环来实现: for(k=L;k>=i;k--)putchar(′ ′); 把此循环放在i控制的循环体内、输出每行字符的循环之前即可。 (8)请读者自己补充有关的include行、语句和变量的定义,以完成整个程序。注意,如果有能力可在某些地方作些简化。 第七章、函数 一、选择题 7.1 以下说法中正确的是 A)C语言程序总是从第一个定义的函数开始执行 B)在C语言程序中,要调用的函数必须在main函数中定义 C)C语言程序总是从main函数开始执行 D)C语言程序中的main函数必须放在程序的开始部分 答案:C 7.2 以下函数的类型是 A)与参数x的类型相同 B)void类型 C)int类型 D)无法确定 fff(float x) { printf(”%d“,x*x);} 答案:C 7.3 以下函数调用语句中,含有的实参个数是 A)1 B)2 C)4 D)5 func((exp1,exp2),(exp3,exp4,exp5)); 答案:B 7.4 以下程序的输出结果是 A)11 B)20 C)21 D)31 fun(int a,int b){ int c; c=a+b; return c; } main(){ int x=6,y=7,z=8,r; r=func((x--,y++,x+y),z--); printf(”%d“,r);} 答案:C 7.5 以下程序的输出结果是 A)-1 B)0 C)1 D)2 main(){ int i=2,p; p=f(i,i+1); printf(”%d“,p);} int f(int a, int b){ int c; c=a; if(a>b)c=1; else if(a==b)c=0; else c=-1; return(c);} 答案:A 7.6 以下程序的输出结果是 A)0 B)1 C)6 D)无定值 fun(int a,int b,int c){ c=a*b; } main(){ int c; fun(2,3,c); printf(”%d“,c);} 答案:D 7.7 以下程序的输出结果是 A)5.500000 B)3.000000 C)4.000000 D)8.25 double f(int n){ int i; double s; s=1.0; for(i=1;i<=n;i++)s+=1.0/i; return s;} main(){ int i,m=3;float a=0.0; for(i=0;i printf(”%f“,a);} 答案:A 二、填空题 7.8 以下程序的输出结果是____。 unsigned fun6(unsigned num){ unsigned k=1; do { k*=num%10; num/=10;} while(num); return k;} main(){ unsigned n=26; printf(”%d“,fun6(n);} 答案:12 7.9 以下程序的输出结果是____。 double sub(double x,double y,double z){ y-=1.0; z=z+x; return z;} main(){ double a=2.5,b=9.0; printf(”%f“,sub(b-a,a,a));} 答案:9.000000 7.10 以下程序的输出结果是____。 fun1(int a,int b){ int c; a+=a;b+=b; c=fun2(a,b); return c*c;} fun2(int a,int b){ int c; c=a*b%3; return c;} main(){ int x=11,y=19; printf(”%d“,fun1(x,y));} 答案:4 7.11 下面pi函数的功能是,根据以下公式返回满足精度ε要求的π的值。请填空。 π/2 = 1 + 1/3 +(1/3)*(2/5)+(1/3)*(2/5)*(3/7)+(1/3)*(2/5)*(3/7)*(4/9)+...double pi(double eps){ double s=0.0,t=1.0; int n; for(_____;t>eps;n++) { s+=t; t=n*t/(2*n+1); } return(2.0*_____);} 答案:n= 1、s 7.12 以下函数用以求x的y次方。请填空。 double fun(double x, int y){ int i;double z; for(i=1;i_____;i++) z=_____; return z;} 答案:<=y、z*x 7.13 以下程序的功能是计算s=0!+1!+2!+3!+...+n!。请填空。 long f(int n){ int i;long s; s=_____; for(i=1;i<=n;i++)s=_____; return s;} main(){ long s;int k,n; scanf(”%d“,&n); s=_____; for(k=0;k<=n;k++)s=s+_____; printf(”%ld“, s);} 答案:1L、s*i、0、f(k) 三、程序调试和编程题 7.14 【分析与解答】 (1)fun函数判断传给形参n的数是否为素数,若是函数返回1,否则返回0。 (2)函数的原意是用变量yes作为判断n是否为素数的标志,是素数,其值为1,否则为0。而所给函数的实际流程却不能实现这一功能,例如,若n的值为15(明显不是素数)时,在for循环中,当k的值为3时,就会执行if子句,yes得0,但for循环并没有终止,接着k为4时就会执行else子句,又使yes得1,由此可见此程序段并不能准确地判断一个数是否为素数;最后确定yes为何值的是for循环的终止值n/2,当n为15时,k的值为n/2等于7,在循环体内将又一次执行else子句,使yes得1,这时循环结束,函数返回1。由此可见所给fun函数不能起到预想的作用。 (3)由上分析可知,对于n的值为15时而言,问题是在一旦yes的值为0,已判断n中的值不是素数时,没有及时退出循环,返回0;因此,若在if子句中添加一条语句:break;就能解决这一问题,把if语句改写如下: if(n%k==0){ yes=0;break;} else yes=1; (4)在所给fun函数中,当n的值为2、3时(都是素数),因为n/2的值为1(大于k中的2),所以不会进入for循环,而直接执行return语句,细心的读者应该可以发现,这时yes没有赋过值,也就是说,返回的是一个不确定的值,这将会导致错误;因此,应当在定义语句中给yes赋初值1: int k,yes=1; 至此fun函数能正确运行。 (5)总结:因为一旦if语句中的表达式:n%k==0的值为1(即可被某数整除),则可以确定n不是素数,因此即可返回,不必再执行函数其他部分,if子句可改成: if(n%k==0){ yes=0;return yes;} else yes=1; 也可简化成: if(n%k==0)return 0; else yes=1; 又可进一步不用变量yes,并去掉else,简化成(请参考例7.4): for(k=2;k<=n/2;k++) if(n%k==0)return 0; return 1; 7.15【分析与解答】 (1)若用整型变量c存放余数,则求a被b除后的余数可用表达式: c=a%b。 (2)本题要求编写函数mymod用以求a被b除后的余数即: c=mymod(a,b); (3)只要把a%b作为函数值返回即可完成操作(请参考例7.1): int mymod(int a, int b) { return a%b;} (4)总结:本题在算法上十分简单,只是要求读者能够掌握编写函数的基本知识。 7.16【分析与解答】 (1)本题所要采用的算法是累加。分析可见,所有累加项的分子都是1,而分母部分逐项增1;只是累加项的符号交叉变化。因此处理好符号的变化是完成操作的关键之一。 (2)若函数名为funa,传送到函数的参数是整型值,假定形参命名为n;函数的返回值应当是浮点型,为此函数的首部可以是: double funa(int n) (3)接着写函数体。累加放在一个for循环中来完成,若循环控制变量为k,可利用循环控制变量作为累加项t的分母,累加值放在add中: for(k=1;k<=n;k++) { „„ t=s*1.0/k; add=add+t; } 此处,s用作符号变量,在1和-1之间交叉变化,乘以1.0/k后,t的值也将按要求变化符号。注意,表达式1.0/k不可以写成1/k,因为每一项的绝对值必定是小于1的小数。 (4)现在需要确定s的值。最简单的可用表达式:s=-s来实现(请参考例5.2),若赋 值号右边s中的值为-1,则赋值号左边s中的值就得1;若赋值号右边s中的值为1,则赋值号左边s中的值就会得-1;则每循环一次就使s改变了一次符号。当然还可有多种方法。把以上表达式添加到循环体中: for(k=1;k<=n;k++) { s=-s; t=s*1.0/k; add=add+t; } (5)最后注意应当给各变量赋以适当的初值,并返回函数值。 (6)请编写主函数。当传给形参的值为10时,函数的返回值应当是:0.645635。 (7)总结:本题的算法并不复杂,但是需要读者掌握编写函数的基本知识。掌握需要传入函。 数的参数及其类型,掌握需要返回的值及其类型。在此基础上,其他方面与先前在主函数中编写的程序没有什么区别。 7.17 【分析与解答】 (1)此题与7.18相似。函数的返回值为浮点型,函数只有一个形参,为整型。 (2)函数的基本算法是累加,只是除第一项外其余各项都用减法;每一项的分子都是1,分母部分为k2,k的值逐项增1,由2变化到m。因此,算法可以用一个循环来实现。(3)当m的值为12时,函数值应是:0.435023。 7.18【分析与解答】 (1)若函数取名为fun,按题意,x作为形参,由调用函数传入,其类型不应当用整型;表达式x2-5x+4的值作为函数值返回,函数值的类型应为浮点型。因此,很容易写出函数: double fun(double x) { return x*x-5*x+4;} (2)若在调用函数时,x和y2已正确定义,且x已有确定的值,则可用以下函数调用语句得到y2的值: y2=fun(x+15); (3)同样,若在调用函数时,x和y3已正确定义,且x已有确定的值,则可用以下函数调用语句得到y3的值: y3=fun(sin(x)); 注意,因为在程序中调用了C语言提供的库函数sin,因此应当在程序的最前面包含以下命令行: #i nclude ″math.h″ (4)参考(2)和(3)应不难写出求y1的语句,请读者自己完成。 (5)y1的值应是:-2.0。当x的值为5时,y2的值应是:304.0。当x的值为0.5时,y3的值应是:1.832721。 (6)总结: ① 本题已给出了函数需要求值的表达式,读者只需确定函数的类型和形参的类型,就可以写出函数,就像例7.1中求两数之和的函数一样简单。 ② 在给定了函数之后,调用函数时,函数的实参应当是一个与形参类型一致的任意合法的 表达式。例如,可以是常量、算术表达式,也可以是函数等。就像例7.1中求两数之和的add函数一样,可以用add(3,4);来求3+4;当x、y有确定值时,可以用add(x*x,y*y);来求x2+y2;当x、y有确定值时,可以用add(sin(x+y),cos(x+y));来求sin(x+y)+cos(x+y),这同样可以通过add(sin(add(x,y)),cos((add(x,y)));来求得。 第八章 指针 一、选择题 8.1 若有定义:int x,*pb;则以下正确的赋值表达式是 A)pb=&x B)pb=x C)*pb=&x 答案: A 8.2 以下程序的输出结果是 A)因变量无定义输出不定值 B)0 C)-1 #include main() { printf(”%d“,NULL); } 答案: B 8.3 以下程序的输出结果是 A)5,2,3 B)-5,-12,-7 C)-5,-12,-17 void sub(int x,int y,int *z) { *z=y-x; } main() { int a,b,c;sub(10,5,&a);sub(7,a,&b);sub(a,b,&c);printf(”%d,%d,%d“,a,b,c); } 答案: B 8.4 以下程序的输出结果是 A)4 B)6 C)8 D)10 main() { int k=2,m=4,n=6;int *pb=&k,*pm=&m,*p;*(p=&n)=*pk*(*pm); D)*pb=*x D)1 D)5,-2,-7 printf(”%d“,n); } 答案: C 8.5 已知指针p的指向如图8.5所示,则执行语句*p++;后,*p的值是 A)20 B)30 C)21 D)31 答案: B 8.6 已知指针p的指向如图8.5所示,则表达式*++p的值是 A)20 B)30 C)21 答案: B 8.7 已知指针p的指向如图8.5所示,则表达式++*p的值是 A)20 B)30 C)21 答案: C 8.8 以下程序的输出结果是 A)23 B)24 C)25 D)26 void prtv(int *x) { printf(”%d“,++*x); } main() { int a=25;prtv(&a); } 答案: D 8.9 以下程序的输出结果是 A)运行出错 B)100 C)a的地址 main() { int **k, *a b=100;a=&b;k=&a;printf(”%d“,**k); } 答案: B 8.10 以下程序的输出结果是 A)4,3 B)2,3 C)3,4 D)3,2 void fun(float *a,float *b) { float w;*a=*a+*a;w=*a;*a=*b; D)31 D)31 D)b的地址 *b=w; } main() { float x=2.0,y=3.0;float *px=&x,*py=&y;fun(px,py);printf(”%2.0f,%2.0f“,x,y); } 答案: C 8.11 以下程序的输出结果是 A)9.000000 B)1.500000 10.500000 void sub(float x,float *y,float *z) { *y=*y-1.0;*z=*z+x; } main() { float a=2.5,b=9.0,*pa,*pb;pa=&a,pb=&b;sub(b-a,pa,pa);printf(”%f“,a); } 答案: C 8.12 以下四个程序中不能对两个整形值进行交换的是 A)main(){ int a=10,b=20; swap(&a,&b); printf(”%d%d“,a,b);} swap(int *p, int *q){ int *t,a; t=&a; *t=*p;*p=*q;*q=*t;} B)main(){ int a=10,b=20; swap(&a,&b); printf(”%d%d“,a,b);} swap(int *p, int *q){ int t; t=*p;*p=*q;*q=t; C)8.000000 D) } C)main(){ int *a,*b; *a=10,*b=20; swap(a,b); printf(”%d%d“,*a,*b);} swap(int *p, int *q){ int t; t=*p;*p=*q;*q=t;} D)main(){ int a=10,b=20; int *x=&a,*y=&b; swap(x,y); printf(”%d%d“,a,b);} swap(int *p, int *q){ int t; t=*p;*p=*q;*q=st;} 答案:C 二、填空题 8.13 以下程序段的输出结果是_____。 int *var,ab; ab=100; var=&ab; printf(”%d“,*var);答案:100 8.14 以下程序的输出结果是_____。 int ast(int x,int y,int *cp,int *dp) { *cp=x+y;*dp=x-y; } main() { int a,b,c,d;a=4;b=3;ast(a,b,&c,&d); printf(”%d %d“,c,d); } 答案:7 1 8.15 若有定义:char ch; ab=*var+10; (1)使指针p可以指向变量ch的定义语句是_____。 答案:char *p=&ch; (2)使指针p可以指向变量ch的赋值语句是_____。 答案:p=&ch; (3)通过指针p给变量ch读入字符scanf函数调用语句是_____。 答案:scanf(”%c“,*p); (4)通过指针p给变量ch的赋字符的语句是_____。 答案:ch=*p; 5)通过指针p输出ch中字符的语句是_____。 答案: printf(”%c“,*p); 8.16 若有如图8.5所示五个连续的int类型的存储单元并赋值如图,且p和s的基类型皆为int,p已指向存储单元a[1]。 (1)通过指针p,给s赋值,使其指向最后一个存储单元a[4]的语句是____。 答案: s=p+3; (2)用以移动指针s,使之指向中间的存储单元a[2]的表达式是____。 答案: s=s-2; (3)已知k=2,指针s已指向存储单元a[2],表达式*(s+k)的值是____。 答案: 50 (4)指针s已指向存储单元a[2],不移动指针s,通过s引用存储单元a[3]的表达式是____。 答案: *(a+1) 5)指针s已指向存储单元a[2],p指向存储单元a[0],表达式s-p的值是____。 答案: 2 6)若p指向存储单元a[0],则以下语句的输出结果是____。 for(i=0;i<5;i++)printf(”%d “,*(p+i)); printf(”“); 答案:10 20 30 40 50 三、编程题 8.17【分析与解答】 (1)若函数名为fun,按题意,函数不返回函数值;函数的形参需要接受传送过来的两个浮点数,因此需要有两个double类型的形参;另外要把它们的和值与差值,通过形参传送回去,这就要求有两个double类型的形参指针,接受传送过来的地址,以便通过指针把和值与差值传送给所指的主函数中的变量。因此函数的首部应当是: void fun(double a, double b, double *p1, double *p2) 这里,a、b、p1、p2是自己取的名。 (2)假设把a、b的和值传送给p1所指的存储单元,可用语句:*p1=a+b;把a、b的差值传送给p2所指的存储单元,可用语句:*p2=a-b。(3)因此函数可写成: void fun(double a,double b,double *p1,double *p2) { *p1=a+b;*p2=a-b;} (4)在主函数中,若有定义语句:double x,y,z1,z2;,且x、y已赋值,则调用fun函数的语句可以是:fun(x,y,&z1,&z2)。 (5)总结:本题所要求的算法极简单,但它要求有两个值返回,用return语句就不可能返回两个函数值。要求读者能利用形参指针把要求的值间接地传回调用函数。 8.18【参考答案】 (1)若函数名为maxandmin,按题意,函数不返回函数值;函数将接受3个数(假定为int类型),并需要通过指针指向主函数中的两个int型变量,以便把最大值和最小值放入指针所指的存储单元中。因此函数的首部应当是: void maxandmin(int a,int b,int c,int *pmax,int *pmin) (2)函数体中需要实现求3个数的最大值和最小值的算法,此算法应当在学习第四章时已经掌握(可参考例4.2和习题4.24)。如果把a、b、c中的最大值暂时放在max中,把最小值放在min中,可用以下算法找到最大值: ① 假定a中的数最大,把a赋给max。 ② 用b去和max比较,若b大于max,则把b赋给max;若不大于max,则什么也不做。 ③ 用c去和max比较,若c大于max,则把c赋给max;若不大于max,则什么也不做。 ④ 经过以上操作,max中已放入了a、b、c三个数中的最大数。 ⑤ 可模仿以上算法找到最小值: min=a; if(b (3)若最大值已放入max中,最小值已放入min中,则可用以下语句把最大和最小值放入指针pmax和pmin所指的存储单元中: *pmax=max;*pmin=min; (4)若主函数中已把3个数放入x、y、z中,要求把最大值放入m中,把最小值放在n中,则调用语句应当是: maxandmin(x,y,x,&m,&n); (5)总结:本题要求的算法在第四章应当已掌握,本题的主要目的是要求读者掌握如何通过指针把函数中的多个结果传回主函数。 第九章 数组 一、选择题 9.1 若已定义: int a[ ]={0,1,2,3,4,5,6,7,8,9},*p=a,i; 其中0≤i≤9,则对a数组元素的引用不正确的是 A)a[p-a] B)*(&a[i])C)p[i] D)*(*(a+i)) 答案:D 9.2 以下程序段给数组所有元素输入数据,应在下划线处填入的是 A)a+(i++)B)&a(i+1) C)a+i D)&a[++i] main() { int a[10],i=0;while(i<10)scanf(”%d“,_________); ...} 答案:D 9.3 以下程序的输出结果是 A)3 B)4 C)1 D)2 main() { int a[10]={1,2,3,4,5,6,7,8,9,10},*p=a;printf(”%d“,*(p+2)); } 答案:A 9.4、以下程序的输出结果是 A)不确定的值 B)3 C)2 D)1 main() { int n[2]={0},i,j,k=2;for(i=0;i for(j=0;j } 答案: A 9.5 以下程序的输出结果是 A)17 B)18 C)19 D)20 main() { int a[ ]={2,4,6,8,10},y=1,x,*p;p=&a[1];for(x=0;x<3;x++)y+=*(p+x);printf(”%d“,y); } 答案: C 9.6 以下程序的输出结果是 A)6 B)8 C)4 D)2 main() { int a[10]={2,4,6,8},*p=a,i;for(i=0;i<4;i++)a[i]=*p++;printf(”%d“,a[2]); } 答案:A 9.7 以下程序的输出结果是 A)720 B)120 C)24 D)6 f(int b[ ],int n) { int i,r=1;for(i=0;i<=n;i++)r=r*b[i];return r; } main() { int x,a[]={2,3,4,5,6,7,8,9};x=f(a,3);printf(”%d“,x); } 答案:B 9.8 以下程序中若第一个printf语句输出的是194,则第二个printf语句的输出结果是 A)212 B)204 C)1a4 D)1a6 main() { int a[]={1,2,3,4,5,6,7,8,9,0},*p;p=a;printf(”%x“,p);printf(”%x“,p+9); } 答案:D 9.9 以下程序的输出结果是 A)0987654321 B)4321098765 C)5678901234 D)0987651234 fun(int *s,int n1,int n2) { int i,j,t;i=n1;j=n2;while(i t=*(s+i);*(s+i)=*(s+j);*(s+j)=t; i++;j--;} } main() { int a[10]={1,2,3,4,5,6,7,8,9,0},*p=a,i;fun(p,0,3);fun(p,4,9);fun(p,0,9);for(i=0;i<10;i++)printf(”%d“,*(a+i)); } 答案: C 9.10 以下程序的输出结果是 A)4 4 B)2 2 C)2 4 D)4 6 main() { int a[5]={2,4,6,8,10},*p,**k;p=a; k=&p;printf(”%d “,*(p++));printf(”%d“,**k); } 答案: C 9.11 当运行以下程序时输入三行,每行都是在第一列上开始, a b cdef 则程序的输出结果是 A)abcdef B)a C)a D)a b b b c cd cdef d e f #include ”stdio.h“ #define N 6 main() { char c[N]; int i=0;for(i=0;i } 答案: C 9.12 若有定义和语句: int c[4][5],(*cp)[5]; cp=c; 则对c数组元素的引用正确的是 A)cp+1 B)*(cp+3) C)*(cp+1)+3 D)*(cp+2) 答案: D 9.13 若已定义: int a[4][3]={1,2,3,4,5,6,7,8,9,10,11,12},(*prt)[3]=a,*p=a[0]; 则能正确表示数组元素a[1][2]的表达式是 A)*((*prt+1)[2] B)*(*(p+5))C)(*prt+1)+2 D)*(*(a+1)+2) 答案: D 9.14 若有定义和语句: int a[4][3]={1,2,3,4,5,6,7,8,9,10,11,12},(*prt)[3]=a,*p[4],i; for(i=0;i<4;i++)p[i]=a[i]; 则不能够正确表示a数组元素的表达式是 A)a[4][3] B)p[0][0] C)prt[2][2] D)(*(p+1))[1] 答案: A 9.15 以下程序的输出结果是 A)23 B)26 C)33 D)36 main() { int aa[3][3]={{2},{4},{6}},i,*p=&aa[0][0];for(i=0;i<2;i++){ if(i==0) aa[i][i+1]=*p+1; else ++p; printf(”%d“,*p);} printf(”“); } 答案: A 9.16 以下程序的输出结果是 A)60 B)68 C)99 D)108 main() { int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23};int(*p)[4]=a,i,j,k=0;for(i=0;i<3;i++) for(j=0;j<2;j++) k+=*(*(p+i)+j);printf(”%d“,k); } 答案: A 9.17 以下程序的输出结果是 A)1,5,9,B)1,4,7,C)3,5,7,D)3,6,9,main() { int i,x[3][3]={1,2,3,4,5,6,7,8,9};for(i=0;i<3;i++)printf(”%d,“,x[i][2-i]); } 答案: C 9.18 若有定义语句 int(*p)[M];其中的标识符p是 A)M个指向整型变量的指针 B)指向M个整型变量的函数指针 C)一个指向具有M个整型元素的一维数组指针 D)具有M个指针元素的一维指针数组,每个元素都只能指向整型量 答案: C 二、填空题 9.19 若有以下定义: double w[10]; 则w数组元素下标的上限是____,下限是____。 答案: 9 0 9.20 以下程序的输出结果是____。 main() { int a[]={2,4,6},*prt=&a[0],x=8,y,z;for(y=0;y<3;y++) z=(*(prt+y) } 答案:6 9.21 以下程序的输出结果是____。 main() { int arr[10],i,k=0;for(i=0;i<10;i++)arr[i]=i;for(i=0;i<4;i++)k+=arr[i]+i;printf(”%d“,k); } 答案:12 9.22 以下程序的输出结果是____。 #define N 5 fun(char *s,char a,int n) { int j;*s=a;j=n;while(a } main() { char s[N+1];int k,p;for(k=1;k<=N;k++)s[k]=''''A''''+k+1;printf(”%d“,fun(s,''''E'''',N)); } 答案:3 9.23 若输入3个整数3,2,1,则以下程序的输出结果是____.void sub(int n,int uu[]) { int t;t=uu[n--];t+=3*uu[n];n++;if(t>=10){ uu[n++]=t/10;uu[n]=t%10;} else uu[n]=t; } main() { int i,n,aa[10]={0};scanf(”%d%d%d“,&n,&aa[0],&aa[1]);for(i=1;i } 答案: 2721 9.24 以下程序的输出结果是____.main() { int i,j,row,col,m;int arr[3][3]={{100,200,300},{28,72,-30},{-850,2,6}};m=arr[0][0];for(i=0;i<3;i++) for(j=0;j<3;j++) if(arr[i][j] { m=arr[i][j];row=i;col=j;} printf(”%d,%d,%d“,m,row,col); } 答案:-850,2,0 9.25 以下findmax返回数组s中最大元素的下标,数组中元素的个数由t传入,请填空。 findmax(int s[],int t) { int k,p;for(p=0,k=p;p if(s[p]>s[k])____;return ____; } 答案: k=p k 9.26 以下程序统计从终端输入的字符中每个大写字母的个数,num[0]中统计字母A的个数, 其它依次类推.用#号结束输入,请填空.#include ”stdio.h“ #include ”ctype.h“ main() { int num[26]={0},i;char c;while(____!=''''#'''') if(isupper(c)) num[___]+=1;for(i=0;i<26;i++) if(num[i])printf(”%c: %d“,i+''''A'''',num[i]); } 答案:(c=getchar())c-''''A''' 三、上机题 9.27【分析与解答】 (1)对于字符的输入可参考教材例6.3和习题9.26中的while循环,只是要注意,循环的终止条件是:等于′\[KG-*3]n′。 (2)在while循环体中,用if条件来判断是否为数字字符,若是,就使对应的元素增1;if中的条件表达式可用C的库函数:isdigit(ch),这时要在程序前加:#i nclude (3)若用num数组元素来进行统计,当ch中是数字“0”时,使num[0]增 1、当ch中是数字 “1”时,使num[1]增1„„num的下标表达式可用:ch-′0′。 (4)注意,在定义数组时,数组的大小应符合使用的要求。在利用数组元素作为计数器时,不要忘记首先应该给数组元素赋0值。 (5)总结:通过本题的编程,要求掌握利用数组元素作为计数器的基本算法。 9.28【分析与解答】 本题的编程请参考例9.8。(1)若有以下10个整数: 0 1 2 3 4 5 6 7 8 9 要求从第5个元素依次向前移,则移动之后的数列应该是: 0 1 2 4 5 6 7 8 9 第5个元素不是指下标为5的元素,而是指排列的顺序,对此数列而言是指数值为4的那个。(2)完成移动后,数列中的数据个数减1。 (3)若进行指定操作的函数名为moves,则函数的首部可如下: void moves(int *a,int n,int *m) 这里a用以指向一维数组的首地址,n接受开始移动的元素的位置,m指向主函数中存放元素个数的变量,因为没有函数值返回,因此函数的类型定义为void。(4)可用以下for循环完成指定的移动: for(i=n-1;i<*m;i[KG-*3]+[KG-*3]+)a[i-1]=a[i]; 注意,应当先把第n个元素(下标为n-1)移到第n-1个元素(下标为n-2)的位置上,依次葱馨到后向前移动。(5)完成移动之后,应使m所指变量中的值减1,表示数列中的数据少了一个;这可由于句: *m=*m-1;来完成。 (6)可设计一个输出函数,在移动前、后调用此函数输出数组中的数据,以便验证操作是否正确。若输出函数名为:outarr,则函数首部可写成: void outarr(int a[], int num) 形参a指向待输出的数组,num接受数组中元素的个数。输出操作可由一个for循环来完成: for(i=0;i printf(″\[KG-*3]n\[KG-*3]n″); 退出循环后的printf语句使上面的输出行结束。 (7)在主函数中定义所需的数组和变量。数组中的值可以在主函数中输入,也可定义一个函数用于输入数据。n的值在主函数中输入,然后调用以上函数。需要注意的是,给n输入的值不能是1,因为第一个元素(下标为0)再向前移,下标就越界了,同时,n的值也不可大于10,因为已指定只有10个元素。(8)总结: ① 对于需要进行多次的操作,如本程序中输出数组元素中的值,应当编写一个独立的函数多次调用,而不应重复地编写代码。虽然该函数中只是一个for循环,似乎在主函数中书写两次也不麻烦,但养成良好的模块化程序设计的风格却是十分重要的。 ② 分析以上例子可见,所规定的操作,实际上删除了数列中的第n-1个元素,因此可见删除操作是由移动操作来完成的。 9.29【分析与解答】 (1)程序要求定义两个数组以便存放原始数据和从中选出的所有奇数。(2)若把函数命名为oods,则函数首部可写成: void odds(int *a,int an,int *b,int *bn) 形参a指向存放原始数据的数组,an存放此数组中数据的个数;b指向另一个数组,此数组中将存放将选出的所有奇数,指针bn指向存放奇数个数的存储单元,因为将通过此指针,把奇数的个数传回主函数。(3)在odds函数中,可通过一个for循环选出所有的奇数: for(i=0;i if(a[i]%2){ b[j]=a[i];j[KG-*3]+[KG-*3]+;} 在for循环中逐个引用原始的数组元素,若元素中的值不能被2除尽(不为0),则把它放入b所指的数组中;j用作b的下标,每放入一个奇数后,j的值加1;注意,j的初值应该置0。 (4)当完成以上操作退出循环时,因为在循环内最后进行了一次j[KG-*3]+[KG-*3]+的操作,所以j的值就是奇数的个数,最后应当把它赋给*bn,以便通过指针bn把奇数的个数传回主函数。 (5)程序需要两次输出数组中元素的值,一次是输出原始数组中的值,一次是输出奇数数组中的值。因此可以使用题9.28中的outarr函数,进行两次调用。 (6)在主函数中应当定义所需的数组和变量,可以在主函数中给数组元素输入数据。 (7)总结:本题的算法很简单,要求读者能够编写独立的模块,并在函数之间熟练地传送数据。 9.30【分析与解答】 (1)例9.9完成了对整数由小到大的排序,而本题是对字符数组中的元素进行由大到小的排序;两者之间并无大的区别,只是数组的类型不同,字符数组中每个元素存放一个字符,字符的大小依据每个字符的ASCII码值的大小。 (2)若函数形参a指向主函数中待排序的数组,由大到小的排序只需改变内循环中if语句的条件表达式即可: if(a[p] (3)排序前后可以调用一个输出函数,输出原始数据和排序后的数据,可参考习题9.28的outarr函数,但注意,这里是对字符数组进行输出。 (4)总结:读者可以参考例9.9,程序基本相同,但在掌握排序算法的基础上,必须独立完成此程序,不要照抄。 9.31【分析与解答】 (1)我们把插入操作命名为函数insert,若待插入的数据放在形参x中,指针a指向主函数中的数组,指针n指向存放数组中元素的个数变量,因为插入后,数组中的数据会增加。函数的首部如下: void insert(int *a,int x,int *n)(2)若数组中原有的有序数列按由小到大排列如下,共12个数: 14 17 18 19 20 22 24 26 29 30 33 若x中的数为21,我们立刻知道应插在何处,插入后数列如下,则插入后变成有13个数: 14 17 18 19 20 21 22 24 26 29 30 33 因此,对于程序来说应当做以下4件事: ① 能根据待插的数据,按“仍然有序的要求”判断出插入的位置。 ② 把位置腾出来,以便放入插入的数据,但原有的数据不能缺少。 ③ 把x中的数放入腾出来的位置中。 ④ 使原有数组中的数据个数增1。 (3)现在来做第一个步骤:确定插入的位置。用变量j来放置该位置在数组中的下标,以下while循环将完成此任务: j=0; while(j<*n && a[j] 因为已经假定数列按由小到大排列,当x的值大于当前的元素a[j]时,应当接着与下一个元素比较(执行j[KG-*3]+[KG-*3]+),直到x的值小于或等于当前的元素a[j]时,x就应当插入到下标为j的元素中,在此之前的所有值都比x小。当x的值小于a[0]时,不进入while循环,j的值为0。x就应当插入到下标为0的元素中。当x的值大于数组中所有的元素时,由条件:j<*n 可知,这时j的值将等于*n并退出循环。x就应当插入到下标为j的元素中。 (4)第二个步骤是要把下标为j的元素后原有的数据移走,但不能改变原来的顺序。那么只能把下标为j至下标为*n-1中的数据依次向后平移;这种平移,应当先把最后的、下标为*n-1的元素中的数据移到下标为*n的元素中,其他依次后移一个单元,直到把a[j]中的值放入a[j+1]中。这可由以下for循环来完成: for(i=*n-1;i>[KG-*3]=j;i--)a[i+1]=a[i];(5)第三个步骤是把x放入a[j]中:a[j]=x; (6)第四步是使存放数据个数的变量中的数增1:*n=*n+1;插入过程到此结束。 (7)可利用习题9.28中的outarr函数,在插入前和插入后两次输出数组元素,以判断操作是否正确。(8)请编写主函数,定义所需的数组和变量,给数组输入一组有序数,正确调用函数。(9)请按题目要求至少对程序运行3次,判断程序是否在各种情况下都能得到正确的结果。 (10)总结:插入算法是程序设计中的一种最基本的算法,希望读者在理解的基础上编写程序。 9.32【分析与解答】 (1)若函数名为change,函数首部如下: void change(int x,int *a, int *n) 形参x中存放一个待转换的十进制数,指针a指向一个一维数组,数组中每一个元素中存放一个0或1代表一位二进制数,指针变量n指向一个整型变量,其中存放在一维数组中二进制位的个数。 (2)函数中定义一个指针变量s,并把a所指的数组的首地址赋给它以便保留。把x每次被2除后的余数放在a当前所指的数组元素中,然后移动指针a指向下一个元素,并使x的值除2;重复此过程,直到x的值为0。可用以下的while循环来进行转换: s=a; while(x) { *a=x%2;a+[KG-*3]+;x=x/2;} 退出循环时,已把转换后的二进制数的每一位上的数放入主函数的数组元素中,但是应当注意,在a[0]中放的是二进制数的最低位,最后放入的是最高位。例如,整数8转换成的二进制数为100,则在a[0]、a[1]中存放的是0,而a[2]中存放的是1。 (3)函数中最后用:*n=a-s;把存放在一维数组中二进制位的个数放入n所指的变量中。因为s已指向主函数中数组的第一个元素(下标为0);在循环中,指针a不断后移,最后指向存放二进制数最高位的元素;所以a-s的值就是已存入数据的元素的个数。 (4)在主函数中输入待转换的十进制数,调用change函数后输出数组元素中的值,注意,因为在a[0]中放的是二进制数的最低位,因此输出的顺序应该从a[n]到a[0]。 9.33【分析与解答】 (1)若函数名为getone,形参指针a指向主函数中存放指定数据的数组。函数的首部如下: void getone(int a[]) (2)函数中变量x用来存放得到的一个随机数,变量n用来存放数组中已放入的不同的随机数的个数,变量i用作下标变量。 (3)所有的工作在一个while循环中完成: while(n<15){„„} 当不同的随机数的个数n的值等于15时退出循环。(4)在以上while循环中需要进行以下4项步骤: ① x=rand()%20;得到一个小于20的随机整数。 ② i=0;准备从下标为0的元素开始去查找数组中是否有与x相同的数,若没有,就把x中的数加入到数组中(放在最后),若有,就什么也不做。 ③ 用以下while循环从头到尾去检查数组中是否有与x值相同的元素: while(i a.当x不等于a[i]时,i[KG-*3]+[KG-*3]+,x再去与下一个元素进行比较,当遇到x等于a[i]时,说明在数组中已经有此数,因此不必再去比较,应当退出循环。 b.当x不等于a[i]时,i的值不断增1;当i的值等于n时,说明x已与数组中所有元素都比较过且都不相同,这时也应退出循环。 ④ 如果i的值等于n时,数组中没有与x相同的元素,因此需要把新的值放入数组中,可用以下语句来实现: if(i==n){ a[n]=x;n[KG-*3]+[KG-*3]+;} 因为已有的数据放在下标为0到n-1的元素中,因此新的数放在a[n]中,然后n[KG-*3]+[ KG-*3]+;即数组中不同数据的个数增1。 (5)接着重新循环,再去产生一个新的随机数,重复以上过程,直到n的值等于15时退出外循环。这时在数组中已放入了15个不同的随机整数。 (6)请在主函数中定义所需的数组和变量。调用getone函数后,可在主函数中输出所得的数据。(7)总结: ① getone函数的主要部分是查找,没有找到才进行下一步操作。 ② C语言提供的库函数rand()每调用一次产生一个0到32767的随机整数,因此ran 9.34【分析与解答】 (1)本题可参考例9.11。 (2)本题可用define命令行定义N来代表一个常量(参考2.2.3节)。可定义4个独立的函数来实现所要求的操作。 第一个函数: void getm(int(*[KG-*3]p)[N]) 用于给二维数组元素赋随机数。形参p是一个行指针,N是二维数组的列数。 第二个函数: void sum(int a[][N],int *rows,int *[KG-*3]cols) 用于求出二维数组每一行元素的和值放在形参指针rows所指的一维数组中,求出二维数组每一列元素的和值放在形参指针cols所指的一维数组中。形参a是一个行指针,N是二维数组的列数。 第三个函数: void diagsum(int a[][N],int *dg1, int *dg2) 用于求出方阵的两个对角线上元素的和值,分别放在形参指针dg1和dg2所指的变量中。形参a是一个行指针,N是二维数组的列数。 第四个函数用于必要的输出,请读者自己设计。 (3)在getm函数中,利用一个双重循环,调用rand函数给二维数组赋值: for(i=0;i (4)在sum函数中,利用一个双重循环,分别求出每行的和值放入rows所指数组中,每列的和值放入cols所指数组中: for(i=0;i { rows[i]+[KG-*3]=a[i][j];cols[i]+[KG-*3]=a[j][i];} 当i=0时,rows[i]+[KG-*3]=a[i][j];通过内循环控制变量j从0到N-1的变化,把下标为0行上的每一个元素的值累加,放入rows所指的、下标为0的数组元素中;而cols[i]+[KG-*3] =a[j][i];通过内循环控制变量j从0到N-1的变化,把下标为0列上的每一个元素的值累加,放入cols所指的、下标为0的数组元素中。其他依次类推。 因为进行累加运算,注意要给每个一维数组置初值0。 (5)在diagsum函数中,通过一个for循环来求得两对角线上元素之和: for(i=0;i 在主对角线上的元素行下标和列下标相同。而在从右到左对角线上的元素,行下标从0变化到N-1;对于列下标,当行下标为0时,列下标为N-i-1,当行下标为1时,列下标也可用表达式N-i-1求得,其他依此类推。(6)请参考例9.11的outdata函数对二维数组和有关数据的输出。 (7)总结:对二维数组的操作,一般可利用一个双重循环来进行。本题虽然有多个任务,但可用函数,每个函数完成一个任务,每个函数都很简单,且都很容易读懂;一定要避免把所有的任务混在一起。 9.35【分析与解答】 (1)要进行相加的两个矩阵(假定为a和b)的行数应当相等,列数应当相等。两个矩阵相加就是把两个矩阵中下标相同的两个元素相加,相加的和值放在第三个矩阵(假定为c)、相同下标的元素中。即:c[i][j]=a[i][j]+b[i][j]。 (2)可以定义一个函数getms(参考题9.34),利用rand()函数给两个矩阵赋值。(3)定义addm函数,对两个矩阵相加: void addm(int(*a)[M], int(*b)[M], int(*[KG-*3]c)[M]) 这里a、b、c是行指针,分别指向三个二维数组(N行M列),要求这三个数组的行和列数相同。和值放在c所指数组中。矩阵相加的操作放在一个双重循环中: for(i=0;i void output(int(*a)[M]) 用双重循环来实现 for(i=0;i { for(j=0;j 可调用三次分别输出a、b、c三个矩阵。 (5)请在主函数中定义数组和所需的变量。调用getms函数得到原始数据,调用addm函数实现矩阵相加,调用输出函数输出三个矩阵。 9.36【分析与解答】 (1)为了输出以上表格,需要定义一个9×9的二维数组。在其中存入九九表中的数据。(2)定义函数gettab,在二维数组中存入九九表中的数据: void gettab(int a[][N]) 形参a是一个指向9×9二维数组的行指针。 (3)在gettab函数中,可用以下for循环把九九表中的数据放入数组中: for(i=0;i for(j=0;j (4)请读者参照前面的习题,设计output函数,输出九九表。表格的第二行: (1)(2)(3)(4)(5)(6)(7)(8)(9) 可用以下语句输出: for(i=1;i<[KG-*3]=9;i[KG-*3]+[KG-*3]+)printf(″(%d)″,i); printf(″\[KG-*3]n″); 在二维数组每一行输出前(即内循环之前)加语句:printf(″(%d)″,i+1);就可得到每一行最前面的(1)、(2)、„、(9)。 (5)输出的格式不可能在第一次调试时就合适,一般需运行几次进行调整。(6)请读者自己完成主函数,定义所需的数组和变量,调用以上的函数。(7)总结:本题的算法很简单,只包含给二维数组的赋值和表格的输出,对于表格的格式,可以通过对程序的运行,逐步进行调整。 9.37【分析与解答】 (1)假定程序定义了M行N列的二维数组。可用define命令行定义N和M来分别代表两个常量(参考2.2.3节)。 (2)程序的功能可由几个独立的函数来实现。 ① void getm(int(*[KG-*3]p)[N])形参p是一个行指针,指向M×N的数组首地址。getm函数的功能是通过调用rand函数给二维数组赋值。请参考习题9.34中的同名函数。 ② void suml(int a[][N],int *rows)形参a是一个行指针,指向M×N的数组首地址,指针rows指向一个一维数组,在此数组元素中将存放每行元素之和。suml函数的功能是求出a所指二维数组中每一行元素之和并依次放在rows所指数组中。请参考习题9.34中的sum函数。 ③ int getmax(int *rows)形参指针rows指向存放每行元素之和的一维数组,在此函数中将求出最大值所在的下标作为函数值返回。请参考习题9.25。 ④ void change(int a[][N],int k)形参行指针a,指向M×N的数组首地址,k接受一维数组中最大值所在的下标。此函数的功能是把二维数组中下标为k的那一行、与下标为0的行的所有元素进行对调。对调可用一个for循环来实现: for(i=0;i { t=a[0][i];a[0][i]=a[k][i];a[k][i]=t;} ⑤ void output(int a[][N])此函数的功能是输出a所指的二维数组。可在数组改变前后分别调用它,以判断程序的操作是否正确。请参考习题9.35中的同名函数。 (4)请在主函数中定义所需的数据结构:如数组、变量,并调用各函数。 (5)总结:交换数据的算法应当已很熟悉,本题只是交换两行中的数据,这时被交换的两个元素的行下标不同,而列下标相同。读者不妨对两列中的数据进行交换。本题中,除对二维数组中的两行进行对调外,其他的算法在此之前都已介绍过,由此可知,应当积累一些基本的算法知识,程序的完成都是由一些基本算法来实现的。 9.38【分析与解答】 (1)在定义数组时应该注意,进行逆置操作的矩阵必须是一个方阵,行、列数相同。 (2)在本题中给二维数组置数以及对二维数组进行输出,请参考习题9.37,在此不再重复。(3)对矩阵进行逆置的操作可由以下函数完成: void transpose(int p[][N]) 形参p指向一个二维数组。逆置的过程可由双重循环来完成: for(i=0;i { t=p[i][j];p[i][j]=p[j][i];p[j][i]=t;} 内循环的控制变量j的变化范围从0到i,以对角线为界,把对称位置上的元素值进行对调。(4)请编写主函数,定义所需的数据结构,并调用函数来实现规定的操作。(5)总结:本题主要的算法也是交换算法,关键是需要正确确定交换的范围。 第十章 字符串 一、选择题 10.1 以下能正确进行字符串赋值,赋初值的语句是 A)char s[5]={''a'',''e'',''i'',''o'',''u''}; B)char *s;s=”good!“; C)char s[5]=”good!“; D)char s[5];s=”good!“; 答案: B 10.2 以下程序段的输出结果是 A)68 B)0 C)字符D的地址 D)不确定的值 char str[]=”ABCD“,*p=str; printf(”%d“,*(p+4)); 答案: B 10.3 以下程序段的输出结果是 A)11 B)10 C)9 D)8 printf(”%d“,strlen(”ATS0121“)); 答案: C 10.4 当运行以下程序时输入OPEN T H E DOOR A)oPEN tHE dOOR B)open the door C)OPEN T H E DOOR D)Open The Door #include ”stdio.h“ char fun(char *c) { if(*c<=''Z''&&*c>=''A'')*c-=''A''-''a'';return *c; } main() { char s[81],*p=s;gets(s);while(*p){ *p=fun(p);putchar(*p);p++;} putchar(''''); } 答案: B 10.5 以下程序的输出结果是 A)GFEDCBA B)AGADAGA C)AGAAGAG D)GAGGAGA #include ”stdio.h“ #include ”string.h“ void fun(char *w,int m) { char s,*p1,*p2;p1=w;p2=w+m-1;while(p1 } main() { char a[]=”ABCDEFG“;fun(a,strlen(a));puts(a); } 答案: C 10.6 以下程序的输出结果是 A)ABCD B)A C)D D)ABCD BCD B C ABC CD C B AB D D A A main() { char s[]=”ABCD“,*p;for(p=s;p } 答案: A 10.7 设有如下定义: char *aa[2]={”abcd“,”ABCD“}; 则以下说法中正确的是 A)aa数组元素的值分别是”abcd“和”ABCD“ B)aa是指针变量,它指向含有两个数组元素的字符型一维数组 C)aa数组的两个元素分别存放的是含有四个字符的一维数组的首地址 D)aa数组的两个元素中各自存放了字符''a''和''A''的地址 答案: C 10.8 以下程序的输出结果是 A)6385 B)69825 C)63825 D)693825 main() { char ch[2][5]={”6937“,”8254“},*p[2];int i,j,s=0;for(i=0;i<2;i++)p[i]=ch[i];for(i=0;i<2;i++) for(j=0;p[i][j]>'' ''&&p[i][j]<=''9'';j+=2) s=10*s+p[i][j]-''0'';printf(”%d“,s); } 答案: A 10.9 以下程序的输出结果是 A)ABCDEFGHIJKL B)ABCD C)ABCDEFGHIJKLMNOP D)AELM main() { char *alpha[6]={”ABCD“,”EFGH“,”IJKL“,”MNOP“,”QRST“,”UVWX“};char **p;int i;p=alpha;for(i=0;i<4;i++)printf(”%s“,p[i]);printf(”“); } 答案: C 10.10 库函数strcpy用以复制字符串。若有以下定义和语句: char str1[]=”string“,str2[8],*str3,*str4=”string“; 则对库函数strcpy的不正确调用是 A)strcpy(str1,”HELLO1“); B)strcpy(str2,”HELLO2“); C)strcpy(str3,”HELLO3“); D)strcpy(str4,”HELLO4“); 答案: C 二、填空题 10.11 以下程序的输出结果是____。 #include ”stdio.h“ main() { char b[]=”ABCDEFG“,*chp=&b[7];while(--chp>&b[0])putchar(*chp);putchar(''''); } 答案: GFEDCB 10.12 以下程序的输出结果是_____。 #include ”stdio.h“ void fun(char *a1,char *a2,int n) { int k;for(k=0;k a2[k]=(a1[k]-''A''-3+26)%26+''A'';a2[n]='' ''; } main() { char s1[5]=”ABCD“,s2[5];fun(s1,s2,4);puts(s2); } 答案:XYZA 10.13 以下程序的输出结果是____。 main() { char *p[]={”BOOL“,”OPK“,”H“,”SP“};int i;for(i=3;i>0;i--,i--)printf(”%c“,*p[i]);printf(”“); } 答案:SO 10.14 当运行以下程序时从键盘输入字符串qwerty和abcd,则程序的输出结果是____。 #include ”string.h“ #include ”stdio.h“ strle(char a[],char b[]) { int num=0,n=0;while(*(a+num)!='' '')num++;while(b[n]){ *(a+num)=b[n];num++;n++;} return(num); } main() { char str1[81],str2[81],*p1=str1,*p2=str2;gets(p1);gets(p2);printf(”%d“,strle(p1,p2)); } 答案:10 10.15 以下程序的输出结果是____。 #include ”string.h“ #include ”ctype.h“ void fun(char str[]) { int i,j;for(i=0,j=0;str[i];i++) if(isalpha(str[i]))str[j++]=str[i];str[j]='' ''; } main() { char ss[80]=”It is!“;fun(ss);printf(”%s“,ss); } 答案:Itiss! 10.16 以下fun函数的功能是将一个字符串的内容颠倒过来,请填空。 #include ”string.h“ void fun(char str[]) { int i,j,k;for(i=0,j=____;i } 答案:strlen(str)-1 j--10.17 以下程序段的输出结果是_____。 printf(”%d“,strlen(”s 160end“)); 答案:3 10.18 以下程序段的输出结果是_____。 char s[20]=”goodgood!“,*sp=s; sp=sp+2; sp=”to“; puts(s); 答案:goodgood! 三、编程题 10.19【分析与解答】 (1)已知gets函数的调用形式为:gets(str),str是存放所读入字符串的起始地址,可以是字符数组名、已指向一串固定存储单元的字符指针或数组元素的地址。gets函数从终端读入一串字符,直到读入一个回车换行符为止,字符串中不包括回车换行符,并在最后自动添加′\0′。现在,在mygets函数中规定用getchar函数进行字符的读入,在此前,我们已多次使用过此函数,并以回车换行符作为结束输入的条件。函数的首部如下: mygets(char *s) 输入过程如下: while((*s=getchar())!=′\n′) s+ +;这里把读入的字符存入s所指的存储单元中,然后移动s,使它指向下一个存储单元。最后当读入′\n′后,结束输入;这时,s指向存放′\n′的存储单元,不要忘记在此单元中放入字符串结束标志来替换′\n′:*s=0。 (2)puts函数的调用形式为:puts(str),str是输出字符串的起始地址。puts函数输出从str地址开始的字符串,最后自动输出一个换行符。myputs函数的首部如下: myputs(char *s) 用以下循环输出字符串中的每一个字符直到遇到字符串结束标志: while(*s){ putchar(*s);s+[KG-*3]+;} 当s所指存储单元中是字符串结束标志时退出循环,然后输出一个换行符:putchar(′\[KG-*3]n′)。 (3)请编写主函数分别调用这两个函数,并分别与gets和puts函数比较。 (4)总结:在mygets函数中利用while循环输入字符的操作在第六章中已多次用到,应当已经熟练掌握;而在myputs函数中利用指针的移动来输出所指存储单元的数据也是应熟练掌握的算法。10.20【分析与解答】 (1)函数首部如下: int fun(char *s) 字符指针形参s指向待查字符串。 (2)定义变量i和j,使其初值分别为0和最后一个字符所在的下标,j的值可通过库函数求得: i=0;j=strlen(s)-1;(3)利用循环,通过i++和j--,使i和j不断分别向后和向前移动,以便引用对称的元素进行比较,若s[i]等于s[j],则当前符合回文条件,i和j的移动继续,否则退出循环;当i大于等于j时,说明对称位置中的字符都已经比较过且符合回文条件,因此也应退出循环: while(i if(i else return 1; (5)请编写主函数,定义所需数据结构,输入不同字符串,调用函数并输出函数值,以判断函数是否正确。(6)总结:本题的算法与逆置算法相似,只是没有对应位置中数据的移动,而是进行比较。 10.21【分析与解答】 (1)本题的算法可参考习题9.28。 (2)若函数名为delc,则函数首部可写成: char delc(char *s, int pos) 因为删除成功要求返回被删的字符,因此函数值的类型应是char。形参字符指针s指向被删字符串的开始,形参pos存放指定的删除位置,注意被删字符的下标就是pos-1。 (3)删除操作实际上是从指定位置开始把字符串中的字符逐个前移,直到遇到字符串结束标志。这一过程可用for循环来完成。先把下标为pos中的字符前移到下标为pos-1的元素中,其他依次前移: for(i=pos;s[i];i[KG-*3]+[KG-*3]+)s[i-1]=s[i]; 退出循环时s[i]中已是字符串结束标志,不要忘记:s[i-1]=s[i];使结束标志也向前移一位。(4)在进行删除操作前,需要检查指定删除位置pos的值是否合理,若不合理就立即返回空值: if(pos>strlen(s)||pos<[KG-*3]=0)return 0; (5)在删除操作前,应该纪录下被删的那个字符,以便作为函数值返回:c=s[pos-1]。 (6)请编写主函数,定义所需的数组和变量,输入字符串和输入删除的位置,调用函数后输出删除后的字符串,并对各种情况进行测试,以检查程序是否正确。 (7)总结:删除算法是程序设计中的基本算法,虽然,在细节的要求上可能有所不同,例如对于一维数组中的数据,需要变动数据的个数,而字符串则要求重新设置字符串结束标志。 10.22【分析与解答】 (1)若函数名为dels,函数首部如下: void dels(char *s) 形参s是一个指向字符串的指针变量。 (2)函数中先完成删除字符串中最后的所有空格。这只要在最后一个非空格字符的后面加上字符串结束标志(′\0′),就使得最后所有的空格都被删除了。但完成这一操作需要通过三个步骤:第一,找到字符串的最后一个空格的位置;第二,往回找到字符串的最后一个非空格的位置;第三,在最后一个非空格的位置的后面加上字符串结束标志。 ① 找到字符串的最后一个空格的位置可用以下语句来完成,函数中另定义一个指针变量p,并把s的值赋给它,使它指向字符串的开始。以下while循环和语句使p指向最后的一个字符(′\0′的前面)。 while(*p)p++; p--; 也可以调用求字符串长度的库函数:p=s+strlen(s)-1;使p指向最后的一个字符。 ② 往回找到字符串的最后一个非空格的位置可用以下语句来完成: while(*p==′ ′)p--; 以上while循环中,只要p所指存储单元中是空格,就使p移动指向前一个字符,当p所指存储单元中不是空格时立刻退出循环;这时p指向字符串中最后一个非空格字符。 ③ 请读者自己把字符串结束标志放在最后一个非空格的位置的后面。 (3)函数接着删除字符串中的前导空格。这只要把前导空格后的第一个非空格字符移到字符串的开头,其后的字符依次前移即可。完成这一操作,首先需要知道第一个非空格字符的位置(下标);然后把其后的字符串移到字符数组的开头。若用变量i来表示第一个非空格字符的下标,i的初值为0,以下循环可以完成此操作: while(s[i]==′ ′)i++; 只要s[i]是空格,就使i增1,直到遇到第一个非空格字符。以下循环把前导空格后的第一个非空格字符移到数组的开头,其后的字符依次前移,直到遇到字符串结束标志。变量j的初值为0,移动完成后,j就是最后一个字符后面元素的下标。请读者自己把字符串结束标志放在其中。 while(s[i]){s[j]=s[i];j++;i++;} (4)请自己编写主函数,给出定义语句。在调用dels函数之后,建议用以下语句输出结果: printf(″\nThe result :\n%s″,str);printf(″****END″); 最后的****END紧跟在字符串之后进行输出,以便观察字符串最后的空格是否已删除。(5)总结:在dels函数中用了移动指针和改变下标两种方法,来引用字符串中的元素。无论是删最后的空格或删前导空格,都可用这两种引用的方法。 第十一章 一、选择题 11.1 以下叙述不正确的是 A)C程序的main函数可以没有参数。 B)C程序的main函数可以有参数。 C)C程序的main函数若有参数时,第一个参数的值最少是1。 D)main函数的第一个参数必须是整型,其名字必须是argv,第二个参数可以定义成:char *argv[],名字必须是argv。 答案:D 11.2 若有以下定义和说明,则对fun函数的正确调用语句是 A)a=fun;a(w); B)a=fun;(*a)(&c); C)b=fun;*b(w); D)fun(b); main() { int(*a)(int *),*b(),w[10],c; ...} fun(int *c){...} 答案:B 11.3 以下叙述正确的是 A)C程序中各函数之间既允许直接递归调用也允许间接递归调用 B)C程序中各函数之间不允许直接递归调用也不允许间接递归调用 C)C程序中各函数之间允许直接递归调用不允许间接递归调用 D)C程序中各函数之间不允许直接递归调用允许间接递归调用 答案:A 11.4 以下程序的输出结果是 A)8 B)30 C)16 D)2 long fib(int n) { if(n>2)return(fib(n-1)+fib(n-2));else return(2); } main() { printf(”%ld“,fib(6));} 答案:C 二、填空题 11.5 假定以下程序经编译和连接后生成可执行文件PROG.EXE,如果在DOS提示符下键入 PROG ABCD EFGH IJKL 则输出结果为_____。 main(int argc, char *argv[]) { while(--argc>0)printf(”%s“,argv[argc]);printf(”“); } 答案:IJKLEFGHABCD 11.6 以下程序的输出结果是_____。 fun(int x) { int p;if(x==0||x==1)return(3);p=x-fun(x-2);return p; } main() { printf(”%d“,fun(9));} 答案:7 11.7 以下程序的输出结果是_____。 fun(int n,int *s) { int f1,f2;if(n==1||n==2)*s=1;else { fun(n-1,&f1); fun(n-2,&f2); *s=f1+f2;} } main() { int x; fun(6,&x);printf(”%d“,x); } 答案:8 11.8 以下程序调用invert函数按逆序重新放置a数组中元素的值,a数组中的值在main函数中读入。请填空。 #define N 10 void invert(int *s,int i, int j) { int t;if(i invert(s,_____,j-1);} } main() { int a[N],i;for(i=0;i } 答案:*(s+j)i+1 i 11.9 以下程序的输出结果是_____。 funa(int a,int b) { return a+b;} funb(int a,int b) { return a-b;} sub(int(*t)(),int x,int y) { return(*t)(x,y);} main() { int x,(*p)(int ,int);p=funa;x=sub(p,9,3);x+=sub(funb,8,3);printf(”%d“,x); } 答案:17 11.10 以下程序中的trap函数是一个用梯形法求定积分的通用函数,梯形法求定积分s的公式为: n-1 x=((f(a)+f(b))/2+∑ f(a+i*h)*h, h=│(a-b)/n│ i=1 其中,n为积分小区间数,以下程序调用trap函数求积分,被积函数是: f(x)=x*x+3*x+2,且 n=1000,a=0,b=4。 #include ”math.h“ double trap(double _____,double a,double b) { double t,h; int i,n=1000;t=0.5*((*fun)(a)+(*fun)(b));h=fabs(a-b)/(double)(n);for(i=1;i<=n-1;i++)t=t+_____;t=t*h;return(t); } double mypoly(double x) { return(x*x+3.0*x+2.0); } main() { double y,(*pf)(double);pf=_____;y=trap(pf,0.0,4.0);printf(”%f",y); } 答案:(*fun)(double)(*fun)(a+i*h)mypoly 三、编程题 11.11 【分析与解答】 (1)无论命令行的内容是什么,总是要求程序需要输出字符串中的一部分连续的字符,因此可将这一部分的功能放在output函数中完成。函数的首部如下: output(char *s, int b,int e) 其中,s指向字符串,b为从s中开始输出的字符的下标,e为结束输出的字符的下标。只要确定了开始输出的字符的下标和结束输出的字符的下标,在一个for循环中就可以完成输出。请自己完成此函数体。 (2)在主函数中读入一行字符串放在s数组中,求出s串的长度放在len变量中。另外用变量n存放要输出的字符的个数。 (3)主函数的首部写成: main(int a, char *[KG-*3]c[]) 其中的第一个参数a将存入命令行中的字符串的个数,当命令行中没有其他参数时,a的值为1;因此按题目要求,此时输出字符的个数n应等于10。 (4)主函数中的第二个参数是一个指向字符串的指针数组。当命令行为: outch-2 这时,c[0]中存放了字符串outch的首地址,c[1]中存放了字符串-2的首地址。存储单元*[KG-*3]c[1](即*(c[1]+0)或c[1][0])中是字符-;存储单元*(c[1]+1)(或c[1][1])中是字符2。同理,当命令行为: outch +6 这时,c[1]中存放了字符串+6的首地址。存储单元*[KG-*3]c[1](即*(c[1]+0))中是字符+;存储单元*(c[1]+1)中是字符6。 (5)根据以上分析,可用以下语句来得到待输出的字符个数放在n中: if(a>1)n=*(c[1]+1)-′0′; else n=10; (6)按题目规定,如果a的值为1或者*[KG-*3]c[1]中的字符是′-′号时,输出s字符串的最后若干字符,这时调用output函数,把s数组的地址传给形参指针s,把开始输出的元素的下标len-n传给形参b,把最后一个输出的元素下标len-1传给形参e。可用以下语句来实现: if(a==1 || *[KG-*3]c[1]==′-′)output(s,len-n,len-1); (7)如果*[KG-*3]c[1]中的字符是′+′号时,将从字符串s的最前面开始输出,除了把s数组的地址传给output函数的形参指针s外,把开始输出的元素的下标0传给形参b,把最后一个输出的元素下标n-1传给形参e。 if(*[KG-*3]c[1]==′+′)output(s,1,n-1); (8)总结:读者按以上所述写出相应的代码,存入OUTCH.C文件。在Turbo C 的环境下进行编译调试、运行,生成一个OUTCH.EXE文件。最后退出Turbo C,在OUTCH.EXE文件所在目录下,打入如题所示的命令行,在程序运行时输入一字符串,观察运行结果是否正确,如果不正确,则需回到Turbo C中进行修改。 11.12 【分析与解答】 习题9.32已经给出了把一个整数转换为二进制数的算法,这是一个把十进制整数不断被2除的过程,每次被2除的余数即是一个二进制位上的数(1或0)。转换的方法是一样的,只是每次转换的数被2除,这可用递归来完成,递归函数的部分内容可表示如下: outbinary(int a) 计算机等级《二级C语言程序设计》预测试卷 (一)一、单项选择题(共40题,合计40分)1以下能正确定义一维数组的选项是()。A.int a[5]={0.1,2.3.4,5); B.char a口={0,1,2,3,4,5); C.char a={'A’,'B','C'); D.int a[5]=”0123”; [正确答案]B 试题解析: 数组下标从0开始,A选项中所赋值的个数超过了数组的长度;c选项中定义a为字符型变量,而不是数组,赋值错误;D选项中,整型数组不能赋字符串。 2视图设计一般有3种设计次序,下列不属于视图设计次序的是()。A.自顶而下 B.由内向外 C.由外向内 D.自底向上 [正确答案]C 试题解析: 视图设计的设计次序分3种:自顶向下、自底向上和由内向外。它们为视图设计提供了具体的操作方法,设计者可根据实际情况灵活掌握。 3链表不具有的特点是()。A.不必事先估计存储空间 B.町随机访问任意元素 C.插入、删除不需要移动元素 D.所需空间与线性表长度成正比 [正确答案]B 试题解析: 链表采用的是链式存储结构,它的结点空间可以动态申请和释放;它的数据元素的逻辑次序靠结点的指针来指示,插入、删除不需要移动数据元素。但是链式存储结构也有不足之处:每个结点中的指针域需额外占用存储空间,它是一种非随机存储结构。 4有以下程序: main(){ int x,i; for(i=l;i<=50;i++){x=i; if(x%2=0)if(x%3=0)if(x%7=0)printf(”%d,i)”; } } 输出结果是()。A.28 B.27 C.42 D.41 [正确答案]C 试题解析: 只有当3个if条件同时成立,即能够同时被2、3、7整除时,才输出i的值,而从0到50能够同时被2、3、7整除的数只有42,故选择C选项。 5若已定义:int a口一(0,1,2,3,4,5,6,7,8,9),*p=a,i;其中0≤i≤9,则对a数组元素的引用不正确的是()。A.a[p-a] B.*(&a[i])C.p[i] D.*(*(a十i))[正确答案]D 试题解析: A:P开始是数组a首地址,只要p++则再减去a的首地址aEp—a]就能取到所有元素,B:&a[i]循环取其地址,*(&a[i])是该地址中所存储的元素C:p就是指针变量,相当于a[i],D:*(a+i)则正确。 6设有下列程序段: char str[]=“HelloWorld”: char*ptr; ptr=str;执行上面的程序段后,*(ptr+10)的值为()。A.'\O' B.'0' C.不确定的值 D.'0'的地址 [正确答案]A 试题解析: 本题主要考查字符数组和指针,在c语言中,字符型数组在存放字符串时会自动在末尾加上' ',所以数组str有ll个元素;ptr指向数组str的首地址,ptr+10是指向str[10],*(ptr+10)是引用strEl0]的值。 7下列4个关于C语言的结论中错误的是()。 A.可以用do while语句实现的循环一定可以用while语句实现 B.可以用for语句实现的循环一定可以用while语句实现 C.可以用while语句实现的循环一定可以用for语句实现 D.do-while语句与while语句的区别仅是关键字“while”出现的位置不同 [正确答案]D 试题解析: 本题考查对各个循环语句的理解。①do—while语句、for语句、while语句所实现的循环可以相互替代;②d0—while语句至少执行一次,而while是符合条件执行,不符合不执行。 8有以下程序: #include {char s[]=“012xyO8s34f4w2‘; int i;n=0;,for(i=0;s[i]!=0;i++)if(s[i]>='0'&&s[i]<='9')n++; printf(”%dn“,n); } 程序运行后的输出结果是()。A.0 B.3 C.7 D.8 [正确答案]B 试题解析: 考查简单的C程序数组和循环。for循环是指i=0,如果s/[3]!=0,则i自动加1。if循环指的是s[i]中的元素大于等于0且小于等于9,则n加l,所以答案为B。 9若有以下说明,则()不是对strcpy库函数正确的调用。strcpy库函数用于复制一个字符串:char*str1==”abed”,strZ[10],*str3=”hijklmn“,*str4[-2],*str5=”aaaa”; A.strcpy(str2,str1)B.strcpy(str3,slrl)C.strcpy(str1,str2) D.strcpy(str5,strl)[正确答案]C 试题解析: strcpy(sl,s2)函数的功能是将字符串s2复制到字符串sl中。要保证sl存储区能容纳下s2字符串。 10数据库系统的核心是()。A.数据模型 B.数据库管理系统 C.数据库 D.数据库管理员 [正确答案]B 试题解析: 本题考查对数据库系统的理解。数据库系统由数据库(数据)、数据库管理系统(软件)、数据库管理员(人员)、硬件平台(硬件)、软件平台5个部分构成。其中数据库管理系统是数据库系统的核心,它负责数据库中的数据组织、数据操纵、数据维护、控制及保护和数据服务等工作。 11有下列函数定义: fun(float h){ printf(”%f,%f\n”,h,h*h);)该函数的类型是()。A.int类型 B.float类型 C.void类型 D.函数无类型说明,定义有错 [正确答案]A 试题解析: 本题考查函数值的类型,在函数定义时,由于函数没有说明其类型,系统默认一律自动按整型(int)处理。 12有以下程序 #include struct tt {int x;struct tt*y;)*P; struct tt a[4]={20,a+1,15,a+2,30,a+3,17,a); main(){ int i; P—a: . for(i=1;i<=2;i++)(printf(”%d,”,p->x);P =P->y:})程序的运行结果是()。A.20,30,B.30,17,C.15,30,D.20,15,[正确答案]D 试题解析: 程序的结构体数组a的元素形成了一个单向的循环链表,每个元素的指针成员都指向下一个元素的地址。有以下程序: main(){ union {char ch[2]; im d; d一0x4321; printf(”%x,%x\n”,s.ch[O],s.ch[1]);)S; 在16位编译系统上,程序执行后的输出结果是()。A.21,43 B.43,21 C.43,00 D.21,00 [正确答案]A 试题解析: s是一个公用体,d的值分别与ch中的两个元素的值相同,d的高位放在eh[1]中、低位放在ch[O]中,因此输出的结果为21,43。 14有以下程序: main(){int a=0,b=0; a=10; /*给a赋值 b=20; 给b赋值 */ printf(”a+b=%d\n”,a+b);//输出计算机结果)程序运行后的输出结果是()。 A.a+b=10 B.a+b=30 C.30 D.出错 [正确答案]A 试题解析: 本题中/*……*/为多行注释,所以可知b=20为注释语句,在程序运行时不起作用,b仍为0,所以本题中选项A正确。 15若有定义:“int a[2][3];”,则对a数组的第i行第j列元素的正确引用为()。A.*(*(a+i)+j)B.(a+i)[j] C.*(a+j+j)D.*(a+i)+j [正确答案]A 试题解析: 通过地址来引用数组元素的方法有下列5种:①a[i][j];②*(a[i]+J);③*(*(a+i)+j);④*(aEiJEj]);⑤(&a[o]EoJ+3*i十j)。故A正确。 16以下程序的输出结果是()。main(){int i,a[4][4]={{1,3,5},{2,4,6},{3,5,7}}; printf(”%d%d%d%d\n”,a[0][3],a[1][2],a[2][1],a[3][0]; } A.0650 B.1470 C.5430 D.输出值不定 [正确答案]A 试题解析: 当所赋的值不够其列的宽度时,系统在其后自动补0,因此a[o][3]=0,a[-1][2]=6,a[2][1]=5,a[3][o]=0,故选择A选项。 17软件生命周期中,花费最多的阶段是()。A.详细设计 B.软件编码 C.软件测试 D.软件维护 [正确答案]D 试题解析: 本题考查对软件生命周期的理解,软件生命周期整体上可分为定义阶段、开发阶段和维护阶段。其中定义阶段包括可行性研究与计划制订和需求分析;开发阶段包括概要设计、详细设计、开发和测试;维护阶段是一个单独阶段,不包含在开发阶段内,它是所花费用最多的一个阶段。 18语句“printf(”a\bre”\'hi\’y\\\bou\n”);”的输出结果是()。A.a\bre\'hi\'y'\\\bou B.a\bre\'hi\\y\bou C.re'hi'you D.abre'hi'y\bou [正确答案]C 试题解析: 先输出a、b表示退一格,当执行到:\b后,1光标往后退,接着输出re’hi’y\(反斜杠后又加一个反斜杠的意思是要输出一个反斜杠),此时又执行:\b后,\就被OU 覆盖。 19有以下程序 #include 试题解析: 本程序主要考查递归函数。fun(7),首先将参数代入函数,因为(7/2)>1,所以执行f(3),依此类推直到f(1.5),(1.5/2)<1,所以执行打印函数,此时X值为3,然后退出f(1.5),返回f(3),打印x值即7。所以选D。 20下列运算符中优先级最低的算符是()。A.|| B.!= C.<一 D.十 [正确答案]A 试题解析: C语言中规定运算符的优先顺序:一元算术运算符一>二元算术运算符一>关系运算符一>逻辑运算符一>赋值运算符,A项中为逻辑运算符,B项和C项都为关系运算符,D项为一元运算符。因此最低的是A项。 21软件生命周期可分为定义阶段、开发阶段和维护阶段。详细设计属于()。A.定义阶段 B.开发阶段 C.维护阶段 D.上述三个阶段 [正确答案]B 试题解析: 开发阶段在开发初期分为需求分析、总体设计、详细设计3个阶段,在开发后期分为编码、测试两个子阶段。 22有以下程序 #include c1='A'+'8'-'4' c2='A'+'8'-'5';printf(”%C,%dn“,cl,c2); } 已知字母A的ASCIl码为65,程序运行后的输出结果是()。A.E,69 B.D,69 C.E,D D.输出无定值 [正确答案]A 试题解析: 本值输出两个值,%c为输出一个字母,0/4d输出一个数字。“A”的ASCIl码为65,再加 4之后为69,也就是字母E,所以本题A正确。 23设有以下语句: int a=1,b=2,c; c=a^(b<<2); 执行后,c的值为()。A.6 B.7 C.8 D.9 [正确答案]D 试题解析: 本题考查两个知识点,按位异或左移把b左移2位化成二进制c=a^(b<<2)=a^(oooolo<<2)=a^o01000=0000001^001000=9,故选择D。 24设有二元关系R和三元关系s,下列运算合法的是()。A.Rn S B.RU S C.R-S D.R×S [正确答案]D 试题解析: 本题给出的两个关系R与s的表结构是不同的(R是二元关系,S是三元关系),它们不能进行“n、U、一”运算,却可以进行笛卡儿积(×)运算。 25结构化程序设计的3种结构是()。A.顺序结构、选择结构、转移结构 B.分支结构、等价结构、循环结构 C.多分支结构、赋值结构、等价结构 D.顺序结构、选择结构、循环结构 [正确答案]D 试题解析: 结构化程序设计的基本要点:①采用自顶向下、逐步求精的程序设计方法;②任何程序都可由顺序、选择和循环三种基本控制结构构造。 26下面for语句的循环次数为()。for(x=1,y=0;(Y!=19)&&(x<6);x++); A.是无限循环 B.循环次数不定 C.最多执行6次 D.最多执行5次 [正确答案]D 试题解析: 本题考查for循环的使用。根据条件考虑X的取值变化,X从1取到5,可以循环5次,但并不知道Y如何变化,有可能出现Y=l9提前跳出循环的情况,所以最多执行5次。 27下列叙述中正确的是()。 A.可以用关系运算符比较字符串的大小 B.空字符串不占用内存,其内存空间大小是0 C.两个连续的单引号是合法的字符常量 D.两个连续的双引号是合法的字符串常量 [正确答案]D 试题解析: 比较两个字符串大小用函数strcomp(S,t),空字符串有结束符,所以也要占用字节,两个双引号表示的是空字符串。 28以下程序的输出结果是()。void fun(int*a,int i,int j){int t; if(i for(i=0;i<4;i++)printf(”%2d”,x[i]); printf(”\n”);)A.1,2,6,8 B.8,6,2,1 C.8,l,6,2 D.8,6,1,2 试题解析: 本题用了函数调用,fun中if语句成立则进行i,j的交换,用到主函数中则为把下标为0、3,1、2互换,因此,当执行完后x的数组为8,1,6,2,故选择C选项 29设有定义”double a[10],*s=a;“,以下能够代表数组元素a[3]的是()。A.(*s)[3] B.*(s+3)C.*s[3] D.*s+3 [正确答案]B 试题解析: 用带下标的指针变量引用一维数组元素若有以下定义和语句:“int*P,s[10],i;P=s}”,且o≤i<10,可以用&.s[i]、s+i和p+i三种表达式来表示s[i]的地址。同时可以用s[i]、*(s+i)和*(p+i)三种表达式来表示数组元素s[i]。 30下列选项中非法的字符常量是()。A.'\t' B.' 39' C.',' D.'\n' [正确答案]B 试题解析: 水平制表符中,’\t'表示的是横向跳若干格;选项B中,’\039’错误,’\039’是八进制形式表的字符,最大数为7,但其中出现'9',’,’是字符逗号;选项D中,7\n’表示的是换行。 31有以下程序: main(){ int x=102,y=012; printf(”%2d,%2d\n”,x,y); } 执行后输出结果是()。A.10,01 B.02,12 C.102,10 D.02,10 [正确答案]C 试题解析: x的值为十进制数102,而Y的值为八进制数012,根据题意将Y用十进制表示为10%md,m为指定输出数据的宽度,若位数小于m则左端补以空格,若位数大于m则按实际输出,所以答案是C。 32相对于数据库系统,文件系统的主要缺陷有数据关联差、数据不一致性和()。A.可重用性差 B.安全性差 C.非持久性 D.冗余性 [正确答案]D 试题解析: 文件系统所管理的数据文件基本上是分散、相互独立的。相对于数据库系统,以此为基础的数据处理存在3个缺点:数据冗余大、数据的不一致性、程序与数据的依赖性强。 33有以下程序: #include int k,n,i,a[6]={1,2,3,4,5,6}; fp=fopen(”d2.dat“,”w“); for(i=0;i<6;i++)fprintf(fp,”%dn“,a[i]); fclose(fp); fp(i=0;i<3;i++)fscanf(fp,”%d%d“,&k,&n); fclose(fp); printf(”%dn,%dn,k,n); } 程序运行后的输出结果是()。A.1, 2 B.3,4 C.5,6 D.123,456 [正确答案]C 试题解析: 此题是考查fprintf和fscanf,其中fprintf是向文件输出,文件为da2.dat文件,fscanf是向文件输入,所以根据程序循环写入和写出.可知答案为C。 34有以下程序段: int k,j,s; for(k=2;k<6;k++,k++){ s=1; for(j=k;j<6;j++)s+=j;)print[(”%d\n”,s); 程序段的输出结果是()。 A.9 B.1 C.11 D.10 [正确答案]D 试题解析: 因为首先k一2,然后你进行一次循环后,k自增两次,变成4,所以这时候S又成l了。然后当k一4的时候,s=1,j=4,然后执行内层循环,s=1+4,然后j自增等于5,s=5+5,然后J再自增为6,跳出内层循环。k自增两次后等于6,不成立,跳出外层循环。然后输出s的值,即为10。因此正确选项为D。 35下列叙述中正确的是()。 A.软件测试应该由程序开发者来完成 B.程序经调试后一般不需要测试 C.软件维护只包括对程序代码的维护 D.以上三种说法都不对 [正确答案]D 试题解析: 程序调试是由程序开发者完成诊断和改正程序中的错误的过程;软件测试是由专门的测试人员完成,是发现错误而执行程序的过程;软件维护是指软件系统交付使用以后,为了改正错误或满足新的需要而修改软件的过程,是软件生存周期中非常重要的一个阶段。 36若有定义:int X,*pb;则正确的赋值表达式是()。A.pb=&X B.pb=X C.*pb=&x D.*pb=*x [正确答案]A 试题解析: *pb是指解除对*pb的引用(也可以认为是取pb所指向的地址的值),被解除引用的指针可以作为左值,&为取地址运算符,&X就是取指向变量X的指针。 37下列叙述中正确的是()。 A.为了建立一个关系,首先要构造数据的逻辑关系 B.表示关系的二维表中各元组的每一个分量还可以分成若干数据项 C.一个关系的属性名表称为关系模式 D.一个关系可以包括多个二维表 [正确答案]A 试题解析: 元组分量的原子性要求二维表中元组的分量是不可分割的基本数据项。关系的框架称为关系模式。一个称为关系的二维表必须同时满足关系的7个性质。 38设有以下语句 char chl,ch2; scanf(“%c%C”,&chl,&ch2); 若要为变量chl和ch2分别输入字符A和B,正确的输入形式应该是()。A.A和B之间用逗号间隔 B.A和B之间不能有任何间隔符 C.A和B之间可以用回车间隔 D.A和B之间用空格间隔 [正确答案]B 试题解析: scanf输入函数中,格式控制J必须严格按照函数中的要求进行输入,在scanf(“%c%c”,&chl,&ch2)的格式控制语句中没有任何字符进行间隔,所以在输入时也不能使用任何字符进行间隔,所以答案选择B。 39设x=011050,则x=x&01252的值是()。A.000000 1000 101000 B.***1 C.0000001 01 1 100010 D.1100000OOOl0 1 000 [正确答案]A 试题解析: 本题主要考查按位与运算,x—Oll050的二进制形式为O001001000010lo00,01252的二进制形式为***0,两者相与得***0。 40有下列程序: #include main(){ int a=6,b=7,m=1; switch(a%2){ case 0:m++;break; case 1:m++; switch(b%2){default:m++; case 0:m++;break;))printf(”%d\n”,m); 程序的运行结果是()。A.3 B.2 C.4 D.1 [正确答案]B 试题解析: 本题考查switch语句及break的用法。第一个switch语句,因为a=6,a%2=0,所以执行“case0,m++;”,将m加-1,遇到break语句跳出switch语句,结束循环。不执行下面的switch。 二、填空题(共1题,合计18分)41请补充main()函数,该函数的功能是:把一个字符串中的所有小写字母字符全部转换成大写字母字符,其他字符不变,结果保存在原来的字符串中。例如,当str[M]=”abcdefl23ABCD”,结果输出:“ABC DEF123ABCD”。 注意:部分源程序给出如下。 请勿改动main()函数和其他函数中的任何内容,仅在横线上填入所编写的若干表达式或语句。 试题程序: #include #include #include #define M 80 void main(){ intj; char str[M]=“ abcdefl23ABCD”; char *pf=str; system(”CLS”): printf(”***original string *** n”): puts(str); 【1】 while(*(pf+j)){ if(*(pf+j)>='a' &&*(pf+j)<='Z'){ *(pf+j)=【2】 ; 【3】 ;)else j++;)printf(”****new string****n”); puts(str); system(”pause”);} [正确答案]【1】j=0【2】*(pf+j)-321311j++ 试题解析: 由程序中可知,变量j为字符数组的下标,其初始值为0。因此,【l】处填“j=0”;大写字母的ASCIl码值比小写字母的小32,要将小写字母变为大写字母,因此,【2】处填“*(pftj)-32”;要将字符串数组中的所有小写字母变为大写字母,需要检查其中的每一个字符,因此,【3】处填“j++”。 三、改错题(共1题,合计24分)42下列给定程序中,函数proe()的功能是:对M名学生的学习成绩,按从高到低的顺序找出前m(m<10)名学生来,并将这些学生数据存放在一个动态分配的连续存储区中,此存储区的首地址作为函数值返回。 请修改程序中的错误,使它能得出正确的结果。 注意:不要改动main()函数,不得增行或删行,也不得更改程序的结构。试题程序: #include%stdlib.h> #include STU *proc(STU a[],int m){ STU b[-M],*t; int i,j,k; //****found**** *t=calloc(m,sizeof(STU)); for(i=0;i //****found**** t[k].num=b[j].num; t[k].s=b[j].S; b[j].s=0; } return t: } void outresuh(STU a[],FILE *pf)f int i; for(i=0;i system(”CLS”); printf(”****THE RESULT****n”); outresuh(stu,stdout); print{(”nGive the number of the students who have better score:”); scanf(”%d”,&m); while(m>10)printf(”nGive the number of the students who have better score:”); scanf(”%d”,&m); } p()rder=proc(stu,m); printf(”****THE RESULT****n”); printf(”The lop:n”); for(i=0:i (1)错误:*t=ealloc(m,sizeof(STU)); 正确:t=(structSS*)calloc(m,sizeof(STU));(2)错误:t[kJ.num=b[j].num; 正确:t[k]-h[j+; 试题解析: 因为t是指向一个动态存储空间,因此其是指针,而不是其中的内容,故把“*t=calloc(m,sizeof(STU))”改为“t=(structSS*)calloc(m,sizeof(STU));”,而题目要求把学生的全部内容互换,因此即整个结构体,故把“t[k]. num=bl;”改为“t[k]=;”。 四、编程与应用题(共1题,合计18分)43学生的记录由学号和成绩组成,M名学生的数据已在主函数中放入结构体数组stu中,请编写函数proc(),其功能是:按分数的高低排列学生的记录,高分在前。注意:部分源程序给出如下。 请勿改动main()函数和其他函数中的任何内容,仅在函数proc()的花括号中填入所编写的若干语句。试题程序: # include void proc(STREC a[])int i,j; STREC t; for(i=1;i in/i; proc(stu): prinlf(”The data afwr sorted:n”); for(i=0;i printf(”%s%4d”,stu[i].num,stu[i].s); } printf(”n”): } [正确答案]voidproc(STRECa[]){ inti,j; STRECt; for(i=1;i 试题解析: 要按分数的高低排列学生的记录,可以使用冒泡排序法。将每一个学生的成绩与其他学生的成绩相比较,对不符合要求的记录交换位置。 《全国计算机等级考试二级教程——C语言程序设计》 习题分析与详细解答 第一章 程序设计基本概念习题分析与解答 1.1 【参考答案】 EXE 1.2 【参考答案】 [1].C [2].OBJ [3].EXE 1.3 【参考答案】 [1] 顺序结构 [2] 选择结构 [3] 循环结构 第二章 C程序设计的初步知识习题分析与解答 一、选择题 2.1 【参考答案】 B)2.2 【参考答案】 D)2.3 【参考答案】 B)2.4 【参考答案】 A)2.5 【参考答案】 C)2.6 【参考答案】 A)2.7 【参考答案】 B)2.8 【参考答案】 B)2.9 【参考答案】 D)2.10 【参考答案】 C)2.11 【参考答案】 B)2.12 【参考答案】 B)2.13 【参考答案】 A) 二、填空题 2.14 【参考答案】 [1] 11 [2] 12 2.15 【参考答案】 [1] 4.2 [2] 4.2 2.16 【参考答案】 [1] { [2] } [3] 定义 [4] 执行 2.17 【参考答案】 [1] 关键字 [2] 用户标识符 2.18 【参考答案】 [1] int [2] float [3] double 2.19 【参考答案】 float a1=1.0, a2=1.0; 或float a1=1, a2=1;(系统将自动把1转换为1.0)2.20 【参考答案】 存储单元 2.21 【参考答案】 3.5 2.22 【参考答案】 [1] a*b/c [2] a/c*b [3] b/c*a 2.23 【参考答案】 把10赋给变量s 2.24 【参考答案】 [1] 位 [2] 1位二进制数据(0或1)2.25 【参考答案】 [1] 8 [2]127 [3]01111111 [4]-128 [ 5 ] 10000000 2.26 【参考答案】 [1] 32767 [2]-32768 [3] ***0 2.27 【参考答案】 [1] 十 [2] 八 [3] 十六 三、上机改错题 2.28 【分析与解答】 第1行的错误: (1)include是一个程序行,因此在此行的最后不应当有分号(;)。第2行的错误: (1)main()是主函数的起始行,不是语句,因此最后不应当有分号(;)。 (2)在同一行上的/ * main function * / 显然是注释;C语言规定:注释由/*开头,由*/结束,但在*号和/之间不得插入任何空格,而在此处“/ *”和“* /”之间存在空格,因此,/ * main function * /的写法是错误的,而应写成:/* main function */。第3行的错误: (1)在主函数的起始行main()的后面是函数体,函数体由左花括号({}开始。但在函数体的第一行:float的前面缺少了左花括号({}。 (2)在同一行上的/* /*r is radius*/, /* s is area of circular*/ */ 显然是注释;C语言规定:注释由/*开头,由*/结束,并且开头的/*将去找最近的*/去配对,因此在/* /*r is radius*/中,第一个/*与radius后的那个*/配上了对,结果紧跟在后面的那个逗号(,)落在了注释的外面,而构成了一个多余符号,为此,在编译时将报告“语法错”。/* s is area of circular*/ */中第一个*/就结束了注释,第一个*/就成了多余的了。第6行的错误: (1)printf(″%f \n″,s)应当是一条输出语句,但在最后缺少了一个分号。 (2)printf(″%f \n″,s);是程序的最后一条语句,程序应当结束;但缺少了程序体结束所需的右花括号());此右花括号可以放在printf(″%f \n″,s);的后面,也可以放在printf(″%f \n″,s);的下一行上。2.27 【分析与解答】 第2行的错误:在main的后面缺少一对圆括号。第4行的错误:在c=4.0的后面缺少分号。 第6行的错误:在printf(″%f \n″,v)的后面缺少分号。 第三章 顺序结构习题分析与解答 一、选择题 (单选题)3.1 【参考答案】 C)3.2 【参考答案】 C)3.3 【参考答案】 D)3.4 【参考答案】 C)3.5 【参考答案】 D)3.6 【参考答案】 B)3.7 【参考答案】 C)3.8 【参考答案】 D)3.9 【参考答案】 A)3.10 【参考答案】 B)3.11 【参考答案】 C)3.12 【参考答案】 D)3.13 【参考答案】 D)3.14 【参考答案】 A)3.15 【参考答案】 C)3.16 【参考答案】 C)3.17 【参考答案】 C)3.18 【参考答案】 D)把D的答案修改为:scanf(“%8f”,&c);3.19 【参考答案】 C)3.20 【参考答案】 B) 二、填空题 3.21 【参考答案】 (1)-200,2500(2)i=-200,j=2500(3)i=-200 j=2500 3.22 【参考答案】 [1] 12 [2] 0 [3] 0 3.23 【参考答案】 [1] 一条语句 [2] 分号(或;)3.24 【参考答案】 分号(;)3.25 【参考答案】 [1]:100 25.81 1.89234 [2]: 100 x=127, x= 127, x= 177,x= 7f, x= 3.27 【参考答案】 x=127, x=127 , x=$127 ,x=$ 000127, x=%06d 3.28 【参考答案】 a=513.789215,a= 513.79,a= 513.78921500,a= 513.78921500 三、编程题和改错题 3.29 【分析与解答】 (1)主函数名main后应有一对圆括号。 (2)第三行的printf语句用以提示输入,但是原样输出的字符串没有用双引号括起来;另外,从输入的形式看,输入的数据紧跟在提示之后,因此,printf格式串中最后不应该有换行符——\n。 (3)因为输入项a、b、c从定义和计算结果来看都是double类型,因此,第四行scanf语句格式串中的格式说明不应当用%d而应当用%lf;且每一个变量之前应该加地址运算符&。 (4)第七行的printf语句中应当把%d都改成%lf或%f;按输出要求在格式串中应添加相应的原样输出的字符;因为下一个printf的输出从新的一行开始,因此在本输出语句的格式串的最后应当加换行符——\n。 (5)第八行的printf语句中应当把格式串整理合并放在输出项的前面,输出项放在后面,%d都改成%lf或%f;中间的\n删去。 (6)请同学们自己写出修改后的程序,并上机调试。3.30 【分析与解答】 (1)分析:可用算术式560÷60把分钟换算成小时和分钟,商数就是小时数,余数就是分钟数。 (2)确定变量的名字和定义变量的类型:在程序中把小时数放在变量h中,把分钟数放在变量m中。这两个变量的类型可以是整型(本题中采用整型),也可以是实型。 (3)确定所用算法:求560÷60的商数,在C语言中可以用整除的算法,语句是h=560/60。求余数可用求余运算符 %:560%60,其值放入变量m中的语句是:m=560%60。(4)设计输出格式。若输出的形式定为:小时:分钟,则按此形式设计输出语句。(5)把以上内容放在主函数的一对花括号中。(6)编写程序如下: main(){ int h, m;h=560/60;m=560%60;printf(″The result: %3d : %3d\n″, h,m);} 运行结果是: The result: : 20 3.31 【分析与解答】 (1)确定变量的名字和定义变量的类型。若用a存放1500,用b存放350;用q存放商数,用r存放余数,所有变量应定义成int类型。 (2)设计输入语句从终端输入1500和350;在输入语句之前,应当设计一个输出语句,用以提示输入。 (3)可用整除求商数,结果放在变量q中。可用求余运算符%求两数之余数,结果放在变量r中。 (4)设计输出语句。输出a、b、q、r。 (5)把以上内容放在主函数的一对花括号中。 本题的程序与3.30相似,请大家参考上题并根据本题的解释自己编程,并上机调试。3.32 【分析与解答】 (1)定义4个双精度变量a、b、c和ave,变量a、b、c分别存放读入的3个双精度数,ave存放它们的平均值。 (2)设计输入语句,以及在此之前用于提示输入的(printf)语句。(3)设计求平均值的算法,把所求得的平均值放入变量ave中。 (4)设计把变量ave中的数,从小数点后第二位数进行四舍五入的算法。现举例说明:若ave中的数为123.4644,为了保留此值小数点后一位,可用表达式:(int)(123.4644*10)/10.0;依次推算,为了保留此值小数点后二位,可用表达式:(int)(123.4644*100)/100.0;其他依此类推。 (5)若要求对小数点后第二位数进行四舍五入,则可对原数加0.05后再进行以上运算。如要求保留123.4644小数点后一位且对第二位数进行四舍五入,可用表达式:(int)((123.467+0.05)*10)/10.0。注意:分母一定要用实数10.0而不能用整数10,否则就变成整除了;若要求保留123.4644小数点后两位且对第三位数进行四舍五入,可用表达式:(int)((123.467+0.005)*100)/100.0;其他依此类推。(6)设计输出语句。输出a、b、c和ave。(7)把以上内容放在主函数的一对花括号中。(8)编写程序如下: main(){ double a,b,c,ave;printf(″Enter a ,b ,c : ″);scanf(″%lf%lf%lf″, &a, &b, &c);ave=(a+b+c)/3;printf(″ave=%f\n″, ave); /*用以比较四舍五入前后的数据*/ ave=(int)((ave+0.05)*10)/10.0;/*上句也可写成ave=(int)(ave*10+0.5)/10.0;*/ printf(″a=%f, b=%f, c=%f, ave=%f\n″, a,b,c,ave);} 3.33 【分析与解答】 (1)关于对变量中的数进行交换的算法请参考3.7题中的解释和《教程》中有关的例题。(2)定义4个整型变量a、b、c和t,变量a、b、c分别存放读入的3个整数,t用作临时存储单元。(3)设计输入语句,以及在此之前用于提示输入的(printf)语句。(4)输出a、b、c中的值,以便于比较。(5)交换的步骤如下: ① 把c中的值赋给t。② 把b中的值赋给c。③ 把a中的值赋给b。④ 把t中的值赋给a。 经过以上步骤,已按要求进行了交换。(6)输出a、b、c中的值。(7)编写程序如下: main(){ int a, b, c, t;printf(″Enter a, b, c :\n″);scanf(″%d%d%d″,&a,&b,&c);printf(″(1)a=%d,b=%d,c=%d\n″,a,b ,c);t=c;c=b;b=a;a=t;printf(″(2)a=%d,b=%d,c=%d\n″,a,b,c);} 第四章 选择结构习题分析与解答 一、选择题 4.1 【参考答案】 A)4.2 【参考答案】 B)4.3 【参考答案】 A)4.4 【参考答案】 D)4.5 【参考答案】 C)4.6 【参考答案】 A)4.7 【参考答案】 B)4.8 【参考答案】 C)4.9 【参考答案】 D)4.10 【参考答案】 D) 二、填空题 4.11【参考答案】 [1] 非零 [2] 零 4.12【参考答案】 <、>、<=、>=、==、![KG-*2]= 4.13【参考答案】 [1]![2] && [3] [JB>1|][JB>1|] 4.14【参考答案】 [1]:![KG-*2](逻辑非)[2]:<、>、<=、>=(小于、大于、小于等于、大于等于)[3]:==、![KG-*2]=(等于、不等)[4]:&&(逻辑与)[5]:[JB>1|][JB>1|](逻辑或)。4.15【参考答案】 !4.16【参考答案】 [1] a=b 或 a [1] x<=0 [2] 1 4.19【参考答案】 [1] 3 [2] 2 [3] 2 4.20【参考答案】 *# 三、编程题 4.21【分析与解答】 相关内容请参考《教程》4.2节和4.4节。(1)改写如下: switch(a/10){ default : m=5;break;case 0 : case 1 : case 2 : m=1;break;case 3 : m=2;break;case 4 : m=3;break;case 5 : m=4;break;};(2)本题中对a的判断条件有一定的规律可寻;关键是,在switch语句后的表达式中利用了a/10,从而简化了case标号。4.22【分析与解答】 编写本题的程序,首先要解决如何计算学生当前的年龄(设存放实足年龄的变量是age)。(1)如果当前的月份大于生日的月份,则学生的实足年龄age=y1-y0。 (2)如果当前的月份等于生日的月份,就要看日数,当前的日数大于或等于生日的日数,则学生的实足年龄age=y1-y0。 (3)如果不满足以上的条件,就可断定当前的日期没有超过生日日期,就是说学生的年龄应当是age=y1-y0-1。 以上3条,用C语言可以描述如下: if((m1>m0)[JB>1|][JB>1|](m1==m0&&d1>=d0))age=y1-y0;else age=y1-y0-1;读者可以参考以上语句写出程序,也可以根据分析写出与此形式不同的语句和程序。4.23【分析与解答】 (1)若输入的整数a是奇数,输出:odd number,是偶数输出:even number。 (2)若一个a是偶数,它就能被2除尽,即a%2==0,输出even number;若是奇数,它就不能被2除尽,即a%2!〖KG-*2〗=0,输出odd number。 读者可以参考以上给出的算法,写出相应的C语句,并编写出完整的程序。4.24 【分析与解答】 本题的主要算法是从3个数中找出最大的那个数。假定始终把最大的数放在变量max中。(1)假定a中的数最大,把a赋给max。 (2)用b去和max比较,若b大于max,则把b赋给max;若不大于max,则什么也不做。(3)用c去和max比较,若c大于max,则把c赋给max;若不大于max,则什么也不做。(4)经过以上操作,max中已放入了a、b、c三个数中的最大数,输出max即可。读者可以参考以上给出的算法,写出相应的C语句,并编写出完整的程序。4.25 【分析与解答】 (1)本题已给出了非常明确的条件,只要写出正确的条件判断语句就可基本完成程序的编写。(2)由给出的函数可知,只有x的值在规定的范围内时,才求出y的值,因此程序应当对输入的x进行判断,若超过范围就不求y的值。 (3)现以使用if[CD#*2]else语句为例写出程序供参考。main(){ int x,y;printf(″Enter x : ″);scanf(″%d″, &x);if(x>-5&&x<10){ if(x==0)y=x-1;else if(x<10 && x>0)y=x+1;else if(x<0 && x>-5)y=x;printf(″x=%d y=%d\n″, x,y);} printf(″***END***\n\n″);} 第五章 循环结构习题分析与解答 一、选择题 (单选题)5.1 【参考答案】 D)5.2 【参考答案】 C)5.3 【参考答案】 B)5.4 【参考答案】 C)5.5 【参考答案】 C)5.6 【参考答案】 B)5.7 【参考答案】 D)5.8 【参考答案】 A)5.9 【参考答案】 D)5.10【参考答案】 D) 二、填空题 5.11 【参考答案】 [1] 5 [2] 4 [3] 6 5.12 【参考答案】 程序段无限循环,没有输出结果 5.13 【参考答案】 -1 5.14 【参考答案】5.15 【参考答案】 [1] d=1.0 [2] k++ [3] k<=n 5.16 【参考答案】 [1] x>=0 [2] x 三、编程题 5.17【分析与解答】 (1)本题的基本算法是求累加值。累加项的值有规律的递增,每一项的绝对值比前一项增2,因此可以利用循环的控制变量的递增来得到累加项的绝对值。例如: for(i=1;i<=101;i+=2)… (2)按所给的算式可以看到,累加项的符号是在交叉改变的,为此应当在循环体内设 置一个变量,使它的符号按此规律交叉改变,这可用:s=-s;来实现,s的初值为1;当s的值为1时,赋值后s中新的值为-1,当s的值为-1时,赋值后s中新的值为1。用s去乘累加项,将使累加项的符号也随之有规律地改变。 (3)若累加和放在变量sum中,累加项放在变量t中,按照以上叙述,for循环体内的语句可以设计如下: s=-s;t=s*i;sum=sum+t;(4)sum的值是51。 (5)请读者自己对变量做出正确的定义并赋初值,设计输出语句,完善程序。5.18【分析与解答】 (1)本题的基本算法是求累加值。累加项的分子部分都是1;分母的值有规律的递增,依次为1!、2!、„、n!,即,若第i-1项的累加项为 t(i-1),则第i项的累加项是 t(i-1)*i,在程序中可用表达式:t=t/i(i从1变化到n)来表示。(2)根据以上分析,若用变量t来存放累加项,当i的值从1变化到n时,可用以下语句来实 现累加: t=t/i;e+=t;(3)为了实现累加过程,以上语句应当放在循环内,循环控制变量从1变化到n。 (4)若用for循环,按题目要求已指定n的值是50。若用while循环,并没有指定n的值,但已指定了循环结束的条件,当t的值小于10-4结束循环。(5)现例示用while循环来求e值的部分程序: i=1;e=1.0;t=1.0;while(t>=1e-4){ t=t/i;e+=t;i++;}(6)请读者自己对变量做出正确的定义,设计输出语句,完善程序;也可以参考此程序段,按照自己的思路独立地完成程序。(7)e的值应当是:2.71828。 (8)根据以上分析,读者已不难用for循环来实现求e值的计算。 (9)注意:在完成此程序时,不要对分母中的阶乘值进行单独计算,因为17!的值已超过long类型的最大值,更无法求到50!。5.19【分析与解答】 (1)从1880年至2000年的年数可用一个for循环来取得。 (2)对每一年,用以上指定的条件来进行判断,若满足条件即为闰年,进行输出。 (3)按输出的要求,需要设一个变量用于统计一行中输出的个数,若在一行上已连续输出了5个年数,就需输出一个换行符,使下一个输出项在新的一行上开始;若用变量n来做此统计,则当表达式n%5==0时就应输出一个换行符,同时使n重新置0值。(4)若变量y代表年数,if语句的逻辑表达式可以写成如下:(y%4==0 && y%100!=0[JB>1|][JB>1|]y%400==0)(5)以下程序段供参考: for(y=1880;y<=2000;y++)if(y%4==0 && y%100![KG-*2]=0[JB>1|][JB>1|]y%400==0){ printf(″%d ″,y);n++;if(n%5==0){ printf(″\n″);n=0;} }(6)请读者自己对变量做出正确的定义并赋初值,完善程序;也可以参考此程序段,按照自己的思路独立地完成程序。从1880年至2000年有30个闰年。5.20【分析与解答】 (1)不难理解利用以下的for循环可以在一行上连续输出n个*号: for(i=1;i<=n;i++)printf(″*″);printf(″\n″);若n的值是6,则连续输出6个*号。 (2)以上图形是在各行上输出数目不等的*号,只是*号的数目依次有规律地变化。在上半部分各行依次是1、3、5、7个,因此可以用以下的程序段来实现这样的输出: for(k=1;k<=7;k++,k++){ for(i=1;i<=k;i++)printf(″*″);printf(″\n″);} 在下半部依次是5、3、1个;因此可以用以下的程序段来实现这样的输出: for(k=5;k>=1;k--,k--){ for(i=1;i<=k;i++)printf(″*″);printf(″\n″);} 以上程序段从第一列起输出的结果如下: * *** ***** ******* ***** *** * 现在我们已完成了在每行输出指定数目的*号。 (3)输出结果与题目要求不同,它们的区别是:按题目每一行之前有不同的空格,而这里则是所有的行都在第一列上开始输出*号;所以接着就应当解决这一问题。 (4)分析题目要求,每行第一个*号位置的缩进是有规律的,假定中间这一行第一个*号位置是在第一列,则可看出,第一至第三行的缩进分别是3、2、1个空格;而图形下半部的缩进数则刚好相反。这可在以上循环中添加输出连续空格的for循环来实现,对于上半部程序如下: b=3;for(k=1;k<=7;k++,k++){ for(j=1;j<=b;j++)printf(″ ″);b--;for(i=1;i<=k;i++)printf(″*″);printf(″\n″);}(5)请读者在理解以上给出的示例的基础上,自己添加下半部空格的输出。 第六章 字符型数据习题分析与解答 一、选择题 6.1【参考答案】 B)6.2【参考答案】 D)6.3【参考答案】 A)6.4【参考答案】 A)6.5【参考答案】 B)6.6【参考答案】 D)6.7【参考答案】 D)6.8【参考答案】 B)6.9【参考答案】 A)6.10【参考答案】 A)6.11【参考答案】 C) 二、填空题 6.12【参考答案】 -1 6.13【参考答案】6.14【参考答案】 ctype.h 6.15【参考答案】 0 6.16【参考答案】 10A 20B 30C 40D 10A 7.29 101.298AB 7.29 A 7.29B 101.298 三、编程题 6.20【分析与解答】 (1)在进行字符输入时,即使一次输入了一行字符(最后用回车结束输入),字符也只能一个一个地读入。若ch已定义为char型变量,可以用以下的程序段来完成操作: ch=getchar();while(ch![KG-*2]=′\n′){ …… ch=getchar();} 当读入的是一个回车符时,循环就结束。循环体内的“„„”符号表示需要在循环体内完成的其他操作。 (2)在循环内要求进行的操作之一是:输出每个字符以及与之对应的ASCII代码值。因此可用以下语句来实现。 printf(″%c : %d ″,ch,ch);(3)在循环内要求进行的另一个操作是:每行只能输出3对字符和与之对应的ASCII代码值。若n已定义为int型变量,则可用来作计数器;使n的初值为0,每输出一次,n的值增1,当n的值为3的整数倍时,额外输出一个换行符。例如: n++;if(n%3==0)putchar(′\n′);(4)把(2)和(3)中给出的语句放在循环体内,并按要求给出正确的定义和初值,就可完成题目所要求的操作。 (5)也可以在while后的一对括号中来完成字符的读入,如while((ch=getchar())![KG-*2]=′\n′)。这时,循环内、外的“ch=getchar();”语句应当去掉。6.21【分析与解答】 (1)一行字符的读入,请参照题6.20(1)和(5)中的解释。循环体内的“„„”符号表示需要在循环体内完成的其他操作。ch=getchar();while(ch![KG-*2]=′\n′){ …… ch=getchar();}(2)在本题中循环体内需要把读入的所有数字字符转换成一个整数。若用变量n来存放这个整数,为了保证有效的存放,应当把它定义成long类型。 (3)要把输入的一串数字字符转换成一个整数,首先需要判断当前读入的字符是否是数字字符,若不是则什么也不做;若是,则进行以下操作: ① 把当前读入的一个字符转换成一个一位整数,这可由语句“d=ch-′0′;”来实现,在这里d是一个整型变量; ② 把d中的一位数归并到n的低位中,这可用语句“n=n*10+d;”来实现。这里所述的操作可由以下语句来完成: if(ch>=′0′&&ch<=′9′){ d=ch-′0′;n=n*10+d;} if语句后一对括号中的判断表达式可以调用字符函数isdigit来实现: if(isdigit(ch)){ d=ch-′0′;n=n*10+d;} if子句的两个语句可以合并成:n=n*10+ch-′0′。(4)把(3)中的语句放入循环中: ch=getchar();while(ch![KG-*2]=′\n′){ if(ch>=′0′&&ch<=′9′)n=n*10+ ch-′0′;ch=getchar();}(5)请自己写出定义语句并赋初值。注意,最后输出n时,应当使用格式说明%ld,而不能使用%d。 6.22【分析与解答】 (1)行数的统计可通过统计输入的′\n′符的个数来完成。 (2)统计的过程应当放在一个while循环体中;判断循环是否进行的条件可以用:((ch=getchar())==EOF)。若用整型变量n作为计数器对′\n′符进行统计,只要读入的字符是′\n′,则n增1。如: while((ch=getchar())![KG-*2]=EOF)if(ch==′\n′)n++;(3)EOF是在stdio.h中预定义了的标识符,在TURBO C的环境下,键入Ctrl+Z(即按住键盘上的Ctrl键,同时按字母Z键)后,敲Enter键,即输入了EOF。6.23【分析与解答】 (1)本题要求的操作同样可在while循环中完成: while((ch=getchar())!=′\n′){ …… } (2)若用整型变量n作为计数器对小写字母进行统计,只要读入的字符是小写字母,则n增1。如: if(ch>=′a′ && ch<=′z′)n++;(3)在退出循环后,输出n的值。(4)请自己完善程序。6.24【分析与解答】 (1)若图案的行数输入到变量L中。 (2)按要求L决定了图形的行数,因此可通过循环来实现L行的输出: for(i=1;i<=L;i++){ …… } 循环体中的“„„”号,代表输出L行的操作。 (3)假定ch中存放了一个字符,我们知道,通过以下循环可以在一行上输出n个字符: for(j=1;j<=n;j++)putchar(ch);putchar(′\n′);注意,在循环后putchar(′\n′);语句不可少,它用以换行。 (4)现在应当解决如何按要求给出每行输出的字符。由图分析,行数(或行号)为1时输出字符A,行数为2时输出字母B„„若输出的字母放在变量ch中,行号取决于外循环的控制变量i,则输出的字母和行号的关系可用表达式:ch=′A′+i-1来表示。当i为1时ch中被赋予字母A,当i为2时ch中被赋予了字母B,其他依此类推。因此,在此表达式后,利用(3)中的循环就解决了各行上输出的字母。 (5)按要求每行输出的字母的个数不同,第二行输出3个字母,第三行输出5个字母,第四行输出7个字母„„(3)中for循环体的执行次数取决于n的值,也就是说n的值决定了每行输出字母的个数。其实,n的值与行号有着密切的关系:n=2*i-1,当i为1时n的值是 1、当i的2时n的值是 3、当i的3时n的值是 5、当i的4时n的值是7。因此在(3)中for循环之前可用此表达式求出n的值。 (6)总结以上分析,我们可得到以下的程序段: for(i=1;i<=L;i++){ ch=′A′+i-1;n=2*i-1;for(j=1;j<=n;j++)putchar(ch);putchar(′\n′);} 若所用的变量都已正确定义,通过输入L的值为5,则程序段在第一列起有以下的输出结果: A BBB CCCCC DDDDDDD EEEEEEEEE 和题目的要求比较已趋接近,不同的是在每行没有适当的缩进。 (7)现在来解决每行的缩进问题。由题中给出的图形可知,若指定输出5行,第一行缩进5个空格,第二行则缩进4个空格,第三行则缩进3个空格,第四行则缩进2个空格,第五行则缩进1个空格。这同样可以由以下的for循环来实现: for(k=L;k>=i;k--)putchar(′ ′);把此循环放在i控制的循环体内、输出每行字符的循环之前即可。 (8)请读者自己补充有关的include行、语句和变量的定义,以完成整个程序。注意,如果有能力可在某些地方作些简化。 第七章 函数习题分析与解答 一、选择题 7.1 【参考答案】 C)7.2 【参考答案】 C)7.3 【参考答案】 B)7.4【参考答案】 C)7.5【参考答案】 A)7.6【参考答案】 D)7.7【参考答案】 A) 二、填空题 7.8【参考答案】7.9【参考答案】 9.0(或9.000000)7.10【参考答案】7.11【参考答案】 [1] n=1 [2] s 7.12【参考答案】 [1] <=y [2] z*x 7.13【参考答案】 [1] 1 [2] s*i [3] 0 [4] f(k) 三、程序调试和编程题 7.14 【分析与解答】 (1)fun函数判断传给形参n的数是否为素数,若是函数返回1,否则返回0。 (2)函数的原意是用变量yes作为判断n是否为素数的标志,是素数,其值为1,否则为0。而所给函数的实际流程却不能实现这一功能,例如,若n的值为15(明显不是素数)时,在for循环中,当k的值为3时,就会执行if子句,yes得0,但for循环并没有终止,接着k为4时就会执行else子句,又使yes得1,由此可见此程序段并不能准确地判断一个数是否为素数;最后确定yes为何值的是for循环的终止值n/2,当n为15时,k的值为n/2等于7,在循环体内将又一次执行else子句,使yes得1,这时循环结束,函数返回1。由此可见所给fun函数不能起到预想的作用。 (3)由上分析可知,对于n的值为15时而言,问题是在一旦yes的值为0,已判断n中的值不是素数时,没有及时退出循环,返回0;因此,若在if子句中添加一条语句:break;就能解决这一问题,把if语句改写如下: if(n%k==0){ yes=0;break;} else yes=1;(4)在所给fun函数中,当n的值为2、3时(都是素数),因为n/2的值为1(大于k中的2),所以不会进入for循环,而直接执行return语句,细心的读者应该可以发现,这时yes没有赋过值,也就是说,返回的是一个不确定的值,这将会导致错误;因此,应当在定义语句中给yes赋初值1: int k,yes=1;至此fun函数能正确运行。 (5)总结:因为一旦if语句中的表达式:n%k==0的值为1(即可被某数整除),则可以确定n不是素数,因此即可返回,不必再执行函数其他部分,if子句可改成: if(n%k==0){ yes=0;return yes;} else yes=1;也可简化成: if(n%k==0)return 0;else yes=1;又可进一步不用变量yes,并去掉else,简化成(请参考例7.4): for(k=2;k<=n/2;k++)if(n%k==0)return 0;return 1;7.15【分析与解答】 (1)若用整型变量c存放余数,则求a被b除后的余数可用表达式: c=a%b。 (2)本题要求编写函数mymod用以求a被b除后的余数即: c=mymod(a,b);(3)只要把a%b作为函数值返回即可完成操作(请参考例7.1): int mymod(int a, int b){ return a%b;}(4)总结:本题在算法上十分简单,只是要求读者能够掌握编写函数的基本知识。7.16【分析与解答】 (1)本题所要采用的算法是累加。分析可见,所有累加项的分子都是1,而分母部分逐项增1;只是累加项的符号交叉变化。因此处理好符号的变化是完成操作的关键之一。 (2)若函数名为funa,传送到函数的参数是整型值,假定形参命名为n;函数的返回值应当是浮点型,为此函数的首部可以是: double funa(int n)(3)接着写函数体。累加放在一个for循环中来完成,若循环控制变量为k,可利用循环控制变量作为累加项t的分母,累加值放在add中: for(k=1;k<=n;k++){ …… t=s*1.0/k;add=add+t;} 此处,s用作符号变量,在1和-1之间交叉变化,乘以1.0/k后,t的值也将按要求变化符号。注意,表达式1.0/k不可以写成1/k,因为每一项的绝对值必定是小于1的小数。(4)现在需要确定s的值。最简单的可用表达式:s=-s来实现(请参考例5.2),若赋 值号右边s中的值为-1,则赋值号左边s中的值就得1;若赋值号右边s中的值为1,则赋值号左边s中的值就会得-1;则每循环一次就使s改变了一次符号。当然还可有多种方法。把以上表达式添加到循环体中: for(k=1;k<=n;k++){ s=-s;t=s*1.0/k;add=add+t;}(5)最后注意应当给各变量赋以适当的初值,并返回函数值。 (6)请编写主函数。当传给形参的值为10时,函数的返回值应当是:0.645635。 (7)总结:本题的算法并不复杂,但是需要读者掌握编写函数的基本知识。掌握需要传入函。数的参数及其类型,掌握需要返回的值及其类型。在此基础上,其他方面与先前在主函数中编写的程序没有什么区别。7.17 【分析与解答】 (1)此题与7.18相似。函数的返回值为浮点型,函数只有一个形参,为整型。 (2)函数的基本算法是累加,只是除第一项外其余各项都用减法;每一项的分子都是1,分母部分为k2,k的值逐项增1,由2变化到m。因此,算法可以用一个循环来实现。(3)当m的值为12时,函数值应是:0.435023。7.18【分析与解答】 (1)若函数取名为fun,按题意,x作为形参,由调用函数传入,其类型不应当用整型;表达式x2-5x+4的值作为函数值返回,函数值的类型应为浮点型。因此,很容易写出函数: double fun(double x){ return x*x-5*x+4;}(2)若在调用函数时,x和y2已正确定义,且x已有确定的值,则可用以下函数调用语句得 到y2的值: y2=fun(x+15);(3)同样,若在调用函数时,x和y3已正确定义,且x已有确定的值,则可用以下函数调用语句得到y3的值: y3=fun(sin(x));注意,因为在程序中调用了C语言提供的库函数sin,因此应当在程序的最前面包含以下命令行: #include ″math.h″ (4)参考(2)和(3)应不难写出求y1的语句,请读者自己完成。 (5)y1的值应是:-2.0。当x的值为5时,y2的值应是:304.0。当x的值为0.5时,y3的值应是:1.832721。(6)总结: ① 本题已给出了函数需要求值的表达式,读者只需确定函数的类型和形参的类型,就可以写出函数,就像例7.1中求两数之和的函数一样简单。 ② 在给定了函数之后,调用函数时,函数的实参应当是一个与形参类型一致的任意合法的 表达式。例如,可以是常量、算术表达式,也可以是函数等。就像例7.1中求两数之和的add函数一样,可以用add(3,4);来求3+4;当x、y有确定值时,可以用add(x*x,y*y);来求x2+y2;当x、y有确定值时,可以用add(sin(x+y),cos(x+y));来求sin(x+y)+cos(x+y),这同样可以通过add(sin(add(x,y)),cos((add(x,y)));来求得。 第八章 指针习题分析与解答 一、选择题 8.1【参考答案】 A)8.2【参考答案】 B)8.3【参考答案】 B)8.4【参考答案】 C)8.5【参考答案】 B)8.6【参考答案】 B)8.7【参考答案】 C)8.8【参考答案】 D)8.9 【参考答案】 B)8.10【参考答案】 C)8.11【参考答案】 C)8.12【参考答案】 C) 二、填空题 8.13【参考答案】 8.14【参考答案】 1 8.15【参考答案】 char *p, *p=ch, p=&ch;scanf(“%c/n”p,);ch=*p;p=&ch;printf(“%c/n”,*p);8.16【参考答案】 *s=*(p+3), *(s-2),50, *s=*(a+1), 2, 10,20,30,40 三、编程题 8.17【分析与解答】 (1)若函数名为fun,按题意,函数不返回函数值;函数的形参需要接受传送过来的两个浮点数,因此需要有两个double类型的形参;另外要把它们的和值与差值,通过形参传送回去,这就要求有两个double类型的形参指针,接受传送过来的地址,以便通过指针把和值与差值传送给所指的主函数中的变量。因此函数的首部应当是: void fun(double a, double b, double *p1, double *p2)这里,a、b、p1、p2是自己取的名。 (2)假设把a、b的和值传送给p1所指的存储单元,可用语句:*p1=a+b;把a、b的差值传送给p2所指的存储单元,可用语句:*p2=a-b。(3)因此函数可写成: void fun(double a,double b,double *p1,double *p2){ *p1=a+b;*p2=a-b;}(4)在主函数中,若有定义语句:double x,y,z1,z2;,且x、y已赋值,则调用fun函数的语句可以是:fun(x,y,&z1,&z2)。 (5)总结:本题所要求的算法极简单,但它要求有两个值返回,用return语句就不可能返回两个函数值。要求读者能利用形参指针把要求的值间接地传回调用函数。8.18【参考答案】 (1)若函数名为maxandmin,按题意,函数不返回函数值;函数将接受3个数(假定为int类型),并需要通过指针指向主函数中的两个int型变量,以便把最大值和最小值放入指针所指的存储单元中。因此函数的首部应当是: void maxandmin(int a,int b,int c,int *pmax,int *pmin)(2)函数体中需要实现求3个数的最大值和最小值的算法,此算法应当在学习第四章时已经掌握(可参考例4.2和习题4.24)。如果把a、b、c中的最大值暂时放在max中,把最小值放在min中,可用以下算法找到最大值: ① 假定a中的数最大,把a赋给max。 ② 用b去和max比较,若b大于max,则把b赋给max;若不大于max,则什么也不做。③ 用c去和max比较,若c大于max,则把c赋给max;若不大于max,则什么也不做。④ 经过以上操作,max中已放入了a、b、c三个数中的最大数。⑤ 可模仿以上算法找到最小值: min=a;if(b maxandmin(x,y,x,&m,&n);(5)总结:本题要求的算法在第四章应当已掌握,本题的主要目的是要求读者掌握如何通过指针把函数中的多个结果传回主函数。 第九章 数组习题分析与解答 一、选择题 9.1【参考答案】 D)9.2【参考答案】 A)9.3【参考答案】 A)9.4【参考答案】 A)9.5【参考答案】 C)9.6【参考答案】 A)9.7【参考答案】 B)9.8【参考答案】 D)9.9【参考答案】 C)9.10【参考答案】 C)9.11【参考答案】 C)9.12【参考答案】 D)9.13【参考答案】 D)9.14【参考答案】 A)9.15【参考答案】 A)9.16【参考答案】 A)9.17【参考答案】 C)9.18【参考答案】 C) 二、填空题 9.19【参考答案】 [1]9 [2]0 9.20【参考答案】9.21【参考答案】9.22【参考答案】9.23【参考答案】 2721 9.24【参考答案】 -850,2,0 9.25【参考答案】 [1]k=p [2]k 9.26【参考答案】 [1](c=getchar())[2] c-′A′ 三、上机题 9.27【分析与解答】 (1)对于字符的输入可参考教材例6.3和习题9.26中的while循环,只是要注意,循环的终止条件是:等于′\[KG-*3]n′。 (2)在while循环体中,用if条件来判断是否为数字字符,若是,就使对应的元素增1;if中的条件表达式可用C的库函数:isdigit(ch),这时要在程序前加:#include (3)若用num数组元素来进行统计,当ch中是数字“0”时,使num[0]增 1、当ch中是数字 “1”时,使num[1]增1„„num的下标表达式可用:ch-′0′。 (4)注意,在定义数组时,数组的大小应符合使用的要求。在利用数组元素作为计数器时,不要忘记首先应该给数组元素赋0值。 (5)总结:通过本题的编程,要求掌握利用数组元素作为计数器的基本算法。9.28【分析与解答】 本题的编程请参考例9.8。(1)若有以下10个整数: 0 1 2 3 4 5 6 7 8 9 要求从第5个元素依次向前移,则移动之后的数列应该是: 0 1 2 4 5 6 7 8 9 第5个元素不是指下标为5的元素,而是指排列的顺序,对此数列而言是指数值为4的那个。(2)完成移动后,数列中的数据个数减1。 (3)若进行指定操作的函数名为moves,则函数的首部可如下: void moves(int *a,int n,int *m)这里a用以指向一维数组的首地址,n接受开始移动的元素的位置,m指向主函数中存放元素个数的变量,因为没有函数值返回,因此函数的类型定义为void。(4)可用以下for循环完成指定的移动: for(i=n-1;i<*m;i[KG-*3]+[KG-*3]+)a[i-1]=a[i];注意,应当先把第n个元素(下标为n-1)移到第n-1个元素(下标为n-2)的位置上,依次从前到后向前移动。 (5)完成移动之后,应使m所指变量中的值减1,表示数列中的数据少了一个;这可由于句: *m=*m-1;来完成。 (6)可设计一个输出函数,在移动前、后调用此函数输出数组中的数据,以便验证操作是否正确。若输出函数名为:outarr,则函数首部可写成: void outarr(int a[], int num)形参a指向待输出的数组,num接受数组中元素的个数。输出操作可由一个for循环来完成: for(i=0;i (7)在主函数中定义所需的数组和变量。数组中的值可以在主函数中输入,也可定义一个函数用于输入数据。n的值在主函数中输入,然后调用以上函数。需要注意的是,给n输入的值不能是1,因为第一个元素(下标为0)再向前移,下标就越界了,同时,n的值也不可大于10,因为已指定只有10个元素。(8)总结: ① 对于需要进行多次的操作,如本程序中输出数组元素中的值,应当编写一个独立的函数多次调用,而不应重复地编写代码。虽然该函数中只是一个for循环,似乎在主函数中书写两次也不麻烦,但养成良好的模块化程序设计的风格却是十分重要的。 ② 分析以上例子可见,所规定的操作,实际上删除了数列中的第n-1个元素,因此可见删除操作是由移动操作来完成的。9.29【分析与解答】 (1)程序要求定义两个数组以便存放原始数据和从中选出的所有奇数。(2)若把函数命名为oods,则函数首部可写成: void odds(int *a,int an,int *b,int *bn)形参a指向存放原始数据的数组,an存放此数组中数据的个数;b指向另一个数组,此数组中将存放将选出的所有奇数,指针bn指向存放奇数个数的存储单元,因为将通过此指针,把奇数的个数传回主函数。 (3)在odds函数中,可通过一个for循环选出所有的奇数: for(i=0;i (5)程序需要两次输出数组中元素的值,一次是输出原始数组中的值,一次是输出奇数数组中的值。因此可以使用题9.28中的outarr函数,进行两次调用。 (6)在主函数中应当定义所需的数组和变量,可以在主函数中给数组元素输入数据。 (7)总结:本题的算法很简单,要求读者能够编写独立的模块,并在函数之间熟练地传送数据。 9.30【分析与解答】 (1)例9.9完成了对整数由小到大的排序,而本题是对字符数组中的元素进行由大到小的排序;两者之间并无大的区别,只是数组的类型不同,字符数组中每个元素存放一个字符,字符的大小依据每个字符的ASCII码值的大小。(2)若函数形参a指向主函数中待排序的数组,由大到小的排序只需改变内循环中if语句的条件表达式即可: if(a[p] (3)排序前后可以调用一个输出函数,输出原始数据和排序后的数据,可参考习题9.28的outarr函数,但注意,这里是对字符数组进行输出。 (4)总结:读者可以参考例9.9,程序基本相同,但在掌握排序算法的基础上,必须独立完成此程序,不要照抄。9.31【分析与解答】 (1)我们把插入操作命名为函数insert,若待插入的数据放在形参x中,指针a指向主函数中的数组,指针n指向存放数组中元素的个数变量,因为插入后,数组中的数据会增加。函数的首部如下: void insert(int *a,int x,int *n)(2)若数组中原有的有序数列按由小到大排列如下,共12个数: 11 14 17 18 19 20 22 24 26 29 30 33 若x中的数为21,我们立刻知道应插在何处,插入后数列如下,则插入后变成有13个数: 11 14 17 18 19 20 21 22 24 26 29 30 33 因此,对于程序来说应当做以下4件事: ① 能根据待插的数据,按“仍然有序的要求”判断出插入的位置。② 把位置腾出来,以便放入插入的数据,但原有的数据不能缺少。③ 把x中的数放入腾出来的位置中。④ 使原有数组中的数据个数增1。 (3)现在来做第一个步骤:确定插入的位置。用变量j来放置该位置在数组中的下标,以下while循环将完成此任务: j=0;while(j<*n && a[j] (4)第二个步骤是要把下标为j的元素后原有的数据移走,但不能改变原来的顺序。那么只能把下标为j至下标为*n-1中的数据依次向后平移;这种平移,应当先把最后的、下标为*n-1的元素中的数据移到下标为*n的元素中,其他依次后移一个单元,直到把a[j]中的值放入a[j+1]中。这可由以下for循环来完成: for(i=*n-1;i>[KG-*3]=j;i--)a[i+1]=a[i];(5)第三个步骤是把x放入a[j]中:a[j]=x;(6)第四步是使存放数据个数的变量中的数增1:*n=*n+1;插入过程到此结束。(7)可利用习题9.28中的outarr函数,在插入前和插入后两次输出数组元素,以判断操作是否正确。 (8)请编写主函数,定义所需的数组和变量,给数组输入一组有序数,正确调用函数。 (9)请按题目要求至少对程序运行3次,判断程序是否在各种情况下都能得到正确的结果。(10)总结:插入算法是程序设计中的一种最基本的算法,希望读者在理解的基础上编写程序。9.32【分析与解答】(1)若函数名为change,函数首部如下: void change(int x,int *a, int *n)形参x中存放一个待转换的十进制数,指针a指向一个一维数组,数组中每一个元素中存放一个0或1代表一位二进制数,指针变量n指向一个整型变量,其中存放在一维数组中二进制位的个数。 (2)函数中定义一个指针变量s,并把a所指的数组的首地址赋给它以便保留。把x每次被2除后的余数放在a当前所指的数组元素中,然后移动指针a指向下一个元素,并使x的值除2;重复此过程,直到x的值为0。可用以下的while循环来进行转换: s=a;while(x){ *a=x%2;a+[KG-*3]+;x=x/2;} 退出循环时,已把转换后的二进制数的每一位上的数放入主函数的数组元素中,但是应当注意,在a[0]中放的是二进制数的最低位,最后放入的是最高位。例如,整数8转换成的二进制数为100,则在a[0]、a[1]中存放的是0,而a[2]中存放的是1。 (3)函数中最后用:*n=a-s;把存放在一维数组中二进制位的个数放入n所指的变量中。因为s已指向主函数中数组的第一个元素(下标为0);在循环中,指针a不断后移,最后指向存放二进制数最高位的元素;所以a-s的值就是已存入数据的元素的个数。 (4)在主函数中输入待转换的十进制数,调用change函数后输出数组元素中的值,注意,因为在a[0]中放的是二进制数的最低位,因此输出的顺序应该从a[n]到a[0]。9.33【分析与解答】 (1)若函数名为getone,形参指针a指向主函数中存放指定数据的数组。函数的首部如下: void getone(int a[])(2)函数中变量x用来存放得到的一个随机数,变量n用来存放数组中已放入的不同的随机数的个数,变量i用作下标变量。 (3)所有的工作在一个while循环中完成: while(n<15){……} 当不同的随机数的个数n的值等于15时退出循环。(4)在以上while循环中需要进行以下4项步骤: ① x=rand()%20;得到一个小于20的随机整数。 ② i=0;准备从下标为0的元素开始去查找数组中是否有与x相同的数,若没有,就把x中的数加入到数组中(放在最后),若有,就什么也不做。 ③ 用以下while循环从头到尾去检查数组中是否有与x值相同的元素: while(i a.当x不等于a[i]时,i[KG-*3]+[KG-*3]+,x再去与下一个元素进行比较,当遇到x等于a[i]时,说明在数组中已经有此数,因此不必再去比较,应当退出循环。 b.当x不等于a[i]时,i的值不断增1;当i的值等于n时,说明x已与数组中所有元素都比较过且都不相同,这时也应退出循环。 ④ 如果i的值等于n时,数组中没有与x相同的元素,因此需要把新的值放入数组中,可用以下语句来实现: if(i==n){ a[n]=x;n[KG-*3]+[KG-*3]+;} 因为已有的数据放在下标为0到n-1的元素中,因此新的数放在a[n]中,然后n[KG-*3]+[ KG-*3]+;即数组中不同数据的个数增1。 (5)接着重新循环,再去产生一个新的随机数,重复以上过程,直到n的值等于15时退出外循环。这时在数组中已放入了15个不同的随机整数。(6)请在主函数中定义所需的数组和变量。调用getone函数后,可在主函数中输出所得的数据。 (7)总结: ① getone函数的主要部分是查找,没有找到才进行下一步操作。 ② C语言提供的库函数rand()每调用一次产生一个0到32767的随机整数,因此rand()%20将得到一个0到19的随机整数。9.34【分析与解答】(1)本题可参考例9.11。 (2)本题可用define命令行定义N来代表一个常量(参考2.2.3节)。可定义4个独立的函数来实现所要求的操作。第一个函数: void getm(int(*[KG-*3]p)[N])用于给二维数组元素赋随机数。形参p是一个行指针,N是二维数组的列数。第二个函数: void sum(int a[][N],int *rows,int *[KG-*3]cols)用于求出二维数组每一行元素的和值放在形参指针rows所指的一维数组中,求出二维数组每一列元素的和值放在形参指针cols所指的一维数组中。形参a是一个行指针,N是二维数组的列数。 第三个函数: void diagsum(int a[][N],int *dg1, int *dg2)用于求出方阵的两个对角线上元素的和值,分别放在形参指针dg1和dg2所指的变量中。形参a是一个行指针,N是二维数组的列数。 第四个函数用于必要的输出,请读者自己设计。 (3)在getm函数中,利用一个双重循环,调用rand函数给二维数组赋值: for(i=0;i for(i=0;i (5)在diagsum函数中,通过一个for循环来求得两对角线上元素之和: for(i=0;i (6)请参考例9.11的outdata函数对二维数组和有关数据的输出。 (7)总结:对二维数组的操作,一般可利用一个双重循环来进行。本题虽然有多个任务,但 可用函数,每个函数完成一个任务,每个函数都很简单,且都很容易读懂;一定要避免把所有的任务混在一起。9.35【分析与解答】 (1)要进行相加的两个矩阵(假定为a和b)的行数应当相等,列数应当相等。两个矩阵相加就是把两个矩阵中下标相同的两个元素相加,相加的和值放在第三个矩阵(假定为c)、相同下标的元素中。即:c[i][j]=a[i][j]+b[i][j]。 (2)可以定义一个函数getms(参考题9.34),利用rand()函数给两个矩阵赋值。(3)定义addm函数,对两个矩阵相加: void addm(int(*a)[M], int(*b)[M], int(*[KG-*3]c)[M])这里a、b、c是行指针,分别指向三个二维数组(N行M列),要求这三个数组的行和列数相同。和值放在c所指数组中。矩阵相加的操作放在一个双重循环中: for(i=0;i for(i=0;i (5)请在主函数中定义数组和所需的变量。调用getms函数得到原始数据,调用addm函数实现矩阵相加,调用输出函数输出三个矩阵。9.36【分析与解答】 (1)为了输出以上表格,需要定义一个9×9的二维数组。在其中存入九九表中的数据。(2)定义函数gettab,在二维数组中存入九九表中的数据: void gettab(int a[][N])形参a是一个指向9×9二维数组的行指针。 (3)在gettab函数中,可用以下for循环把九九表中的数据放入数组中: for(i=0;i for(i=1;i<[KG-*3]=9;i[KG-*3]+[KG-*3]+)printf(″(%d)″,i);printf(″\[KG-*3]n″);在二维数组每一行输出前(即内循环之前)加语句:printf(″(%d)″,i+1);就可得到每一行最前面的(1)、(2)、„、(9)。 (5)输出的格式不可能在第一次调试时就合适,一般需运行几次进行调整。(6)请读者自己完成主函数,定义所需的数组和变量,调用以上的函数。 (7)总结:本题的算法很简单,只包含给二维数组的赋值和表格的输出,对于表格的格式,可以通过对程序的运行,逐步进行调整。9.37【分析与解答】 (1)假定程序定义了M行N列的二维数组。可用define命令行定义N和M来分别代表两个 常量(参考2.2.3节)。 (2)程序的功能可由几个独立的函数来实现。① void getm(int(*[KG-*3]p)[N])形参p是一个行指针,指向M×N的数组首地址。getm函数的功能是通过调用rand函数给二维数组赋值。请参考习题9.34中的同名函数。② void suml(int a[][N],int *rows)形参a是一个行指针,指向M×N的数组首地址,指针rows指向一个一维数组,在此数组元素中将存放每行元素之和。suml函数的功能是求出a所指二维数组中每一行元素之和并依次放在rows所指数组中。请参考习题9.34中的sum函数。③ int getmax(int *rows)形参指针rows指向存放每行元素之和的一维数组,在此函数中将求出最大值所在的下标作为函数值返回。请参考习题9.25。④ void change(int a[][N],int k)形参行指针a,指向M×N的数组首地址,k接受一维数组中最大值所在的下标。此函数的功能是把二维数组中下标为k的那一行、与下标为0的行的所有元素进行对调。对调可用一个for循环来实现: for(i=0;i (5)总结:交换数据的算法应当已很熟悉,本题只是交换两行中的数据,这时被交换的两个元素的行下标不同,而列下标相同。读者不妨对两列中的数据进行交换。本题中,除对二维数组中的两行进行对调外,其他的算法在此之前都已介绍过,由此可知,应当积累一些基本的算法知识,程序的完成都是由一些基本算法来实现的。9.38【分析与解答】 (1)在定义数组时应该注意,进行逆置操作的矩阵必须是一个方阵,行、列数相同。 (2)在本题中给二维数组置数以及对二维数组进行输出,请参考习题9.37,在此不再重复。(3)对矩阵进行逆置的操作可由以下函数完成: void transpose(int p[][N])形参p指向一个二维数组。逆置的过程可由双重循环来完成: for(i=0;i 第十章 字符串习题分析与解答 一、选择题 10.1 【参考答案】 B)10.2 【参考答案】 B)10.3 【参考答案】 C)10.4 【参考答案】 B)10.5 【参考答案】 C)10.6 【参考答案】 A)10.7 【参考答案】 D)10.8 【参考答案】 A)10.9 【参考答案】 C)10.10【参考答案】 C) 二、填空题 10.11【参考答案】 GFEDCB书上(-chp)改为(--chp)10.12【参考答案】 XYZA 10.13【参考答案】 SO 10.14【参考答案】10.15【参考答案】 Itis 10.16【参考答案】 [1] strlen(str)-1;[2] j--(或--j)10.17【参考答案】10.18【参考答案】 goodgood! 三、编程题 10.19【分析与解答】 (1)已知gets函数的调用形式为:gets(str),str是存放所读入字符串的起始地址,可以是字符数组名、已指向一串固定存储单元的字符指针或数组元素的地址。gets函数从终端读入一串字符,直到读入一个回车换行符为止,字符串中不包括回车换行符,并在最后自动添加' '。现在,在mygets函数中规定用getchar函数进行字符的读入,在此前,我们已多次使用过此函数,并以回车换行符作为结束输入的条件。函数的首部如下: mygets(char *s)输入过程如下: while((*s=getchar())!= 'n')s++;这里把读入的字符存入s所指的存储单元中,然后移动s,使它指向下一个存储单元。最后当读入' '后,结束输入;这时,s指向存放'n'的存储单元,不要忘记在此单元中放入字符串结束标志来替换'n':*s=0。 (2)puts函数的调用形式为:puts(str),str是输出字符串的起始地址。puts函数输出从str地址开始的字符串,最后自动输出一个换行符。myputs函数的首部如下: myputs(char *s)用以下循环输出字符串中的每一个字符直到遇到字符串结束标志: while(*s){ putchar(*s);s+[KG-*3]+;} 当s所指存储单元中是字符串结束标志时退出循环,然后输出一个换行符:putchar(' [KG-*3]n')。 (3)请编写主函数分别调用这两个函数,并分别与gets和puts函数比较。 (4)总结:在mygets函数中利用while循环输入字符的操作在第六章中已多次用到,应当已经熟练掌握;而在myputs函数中利用指针的移动来输出所指存储单元的数据也是应熟练掌握的算法。 10.20【分析与解答】(1)函数首部如下: int fun(char *s)字符指针形参s指向待查字符串。(2)定义变量i和j,使其初值分别为0和最后一个字符所在的下标,j的值可通过库函数求得: i=0;j=strlen(s)-1;(3)利用循环,通过i++和j--,使i和j不断分别向后和向前移动,以便引用对称的元素进行比较,若s[i]等于s[j],则当前符合回文条件,i和j的移动继续,否则退出循环;当i大于等于j时,说明对称位置中的字符都已经比较过且符合回文条件,因此也应退出循环: while(i return 1;(5)请编写主函数,定义所需数据结构,输入不同字符串,调用函数并输出函数值,以判断函数是否正确。 (6)总结:本题的算法与逆置算法相似,只是没有对应位置中数据的移动,而是进行比较。10.21【分析与解答】 (1)本题的算法可参考习题9.28。 (2)若函数名为delc,则函数首部可写成: char delc(char *s, int pos)因为删除成功要求返回被删的字符,因此函数值的类型应是char。形参字符指针s指向被删字符串的开始,形参pos存放指定的删除位置,注意被删字符的下标就是pos-1。 (3)删除操作实际上是从指定位置开始把字符串中的字符逐个前移,直到遇到字符串结束标志。这一过程可用for循环来完成。先把下标为pos中的字符前移到下标为pos-1的元素中,其他依次前移: for(i=pos;s[i];i[KG-*3]+[KG-*3]+)s[i-1]=s[i];退出循环时s[i]中已是字符串结束标志,不要忘记:s[i-1]=s[i];使结束标志也向前移一位。 (4)在进行删除操作前,需要检查指定删除位置pos的值是否合理,若不合理就立即返回空值: if(pos>strlen(s)||pos<[KG-*3]=0)return 0;(5)在删除操作前,应该纪录下被删的那个字符,以便作为函数值返回:c=s[pos-1]。(6)请编写主函数,定义所需的数组和变量,输入字符串和输入删除的位置,调用函数后输出删除后的字符串,并对各种情况进行测试,以检查程序是否正确。 (7)总结:删除算法是程序设计中的基本算法,虽然,在细节的要求上可能有所不同,例如对于一维数组中的数据,需要变动数据的个数,而字符串则要求重新设置字符串结束标志。10.22【分析与解答】 (1)若函数名为dels,函数首部如下: void dels(char *s)形参s是一个指向字符串的指针变量。 (2)函数中先完成删除字符串中最后的所有空格。这只要在最后一个非空格字符的后面加上字符串结束标志(′\0′),就使得最后所有的空格都被删除了。但完成这一操作需要通过三个步骤:第一,找到字符串的最后一个空格的位置;第二,往回找到字符串的最后一个非空格的位置;第三,在最后一个非空格的位置的后面加上字符串结束标志。 ① 找到字符串的最后一个空格的位置可用以下语句来完成,函数中另定义一个指针变量p,并把s的值赋给它,使它指向字符串的开始。以下while循环和语句使p指向最后的一个字符(′\0′的前面)。while(*p)p++;p--;也可以调用求字符串长度的库函数:p=s+strlen(s)-1;使p指向最后的一个字符。② 往回找到字符串的最后一个非空格的位置可用以下语句来完成: while(*p==′ ′)p--;以上while循环中,只要p所指存储单元中是空格,就使p移动指向前一个字符,当p所指存储单元中不是空格时立刻退出循环;这时p指向字符串中最后一个非空格字符。③ 请读者自己把字符串结束标志放在最后一个非空格的位置的后面。 (3)函数接着删除字符串中的前导空格。这只要把前导空格后的第一个非空格字符移到字符串的开头,其后的字符依次前移即可。完成这一操作,首先需要知道第一个非空格字符的位 置(下标);然后把其后的字符串移到字符数组的开头。若用变量i来表示第一个非空格字符的下标,i的初值为0,以下循环可以完成此操作: while(s[i]==′ ′)i++;只要s[i]是空格,就使i增1,直到遇到第一个非空格字符。以下循环把前导空格后的第一个非空格字符移到数组的开头,其后的字符依次前移,直到遇到字符串结束标志。变量j的初值为0,移动完成后,j就是最后一个字符后面元素的下标。请读者自己把字符串结束标志放在其中。 while(s[i]){s[j]=s[i];j++;i++;}(4)请自己编写主函数,给出定义语句。在调用dels函数之后,建议用以下语句输出结果: printf(″\nThe result :\n%s″,str);printf(″****END″);最后的****END紧跟在字符串之后进行输出,以便观察字符串最后的空格是否已删除。 (5)总结:在dels函数中用了移动指针和改变下标两种方法,来引用字符串中的元素。无论是删最后的空格或删前导空格,都可用这两种引用的方法。 第十一章 对函数的进一步讨论习题分析与解答 一、选择题 11.1【参考答案】 D)11.2【参考答案】 B)11.3【参考答案】 A)11.4【参考答案】 C) 二、填空题 11.5 【参考答案】 IJKLEFGHABCD 11.6 【参考答案】11.7 【参考答案】11.8 【参考答案】 [1]*(s+j);[2]i+1;[3] i 11.9 【参考答案】11.10 【参考答案】 [1](*fun)(double)[2](*fun)(a+i*h)[3] mypoly 三、编程题 11.11 【分析与解答】 (1)无论命令行的内容是什么,总是要求程序需要输出字符串中的一部分连续的字符,因此可将这一部分的功能放在output函数中完成。函数的首部如下: output(char *s, int b,int e)其中,s指向字符串,b为从s中开始输出的字符的下标,e为结束输出的字符的下标。只要确定了开始输出的字符的下标和结束输出的字符的下标,在一个for循环中就可以完成输出。请自己完成此函数体。 (2)在主函数中读入一行字符串放在s数组中,求出s串的长度放在len变量中。另外用变量n存放要输出的字符的个数。(3)主函数的首部写成: main(int a, char *[KG-*3]c[])其中的第一个参数a将存入命令行中的字符串的个数,当命令行中没有其他参数时,a的值为1;因此按题目要求,此时输出字符的个数n应等于10。 (4)主函数中的第二个参数是一个指向字符串的指针数组。当命令行为: outch-2 这时,c[0]中存放了字符串outch的首地址,c[1]中存放了字符串-2的首地址。存储单 元*[KG-*3]c[1](即*(c[1]+0)或c[1][0])中是字符-;存储单元*(c[1]+1)(或c[1][1])中是字符2。同理,当命令行为: outch +6 这时,c[1]中存放了字符串+6的首地址。存储单元*[KG-*3]c[1](即*(c[1]+0))中是字符+;存储单元*(c[1]+1)中是字符6。 (5)根据以上分析,可用以下语句来得到待输出的字符个数放在n中: if(a>1)n=*(c[1]+1)-′0′;else n=10;(6)按题目规定,如果a的值为1或者*[KG-*3]c[1]中的字符是′-′号时,输出s字符串的最后若干字符,这时调用output函数,把s数组的地址传给形参指针s,把开始输出的元素的下标len-n传给形参b,把最后一个输出的元素下标len-1传给形参e。可用以下语句来实现: if(a==1 || *[KG-*3]c[1]==′-′)output(s,len-n,len-1);(7)如果*[KG-*3]c[1]中的字符是′+′号时,将从字符串s的最前面开始输出,除了把s数组的地址传给output函数的形参指针s外,把开始输出的元素的下标0传给形参b,把最后一个输出的元素下标n-1传给形参e。 if(*[KG-*3]c[1]==′+′)output(s,1,n-1);(8)总结:读者按以上所述写出相应的代码,存入OUTCH.C文件。在Turbo C 的环境下进行编译调试、运行,生成一个OUTCH.EXE文件。最后退出Turbo C,在OUTCH.EXE文件所在目录下,打入如题所示的命令行,在程序运行时输入一字符串,观察运行结果是否正确,如果不正确,则需回到Turbo C中进行修改。11.12 【分析与解答】 习题9.32已经给出了把一个整数转换为二进制数的算法,这是一个把十进制整数不断被2除的过程,每次被2除的余数即是一个二进制位上的数(1或0)。转换的方法是一样的,只是每次转换的数被2除,这可用递归来完成,递归函数的部分内容可表示如下: outbinary(int a){ int d;d=a%2;„„ outbinary(a/2);„„ } 当a的值不为0时,递归继续;结束递归的条件应当是a等于0。因此应该在函数中给出递归进行的条件: outbinary(int a){ int d;d=a%2;if(a!=0){ outbinary(a/2);„„ } } 剩下的是输出每次得到的二进制位上的数。可以在d=a%2;之后立刻输出d,但是先得到的余数是二进制数的低位,这样输出的二进制数与正确的数是逆着的;因此要求能把先得的数后输出才是正确的转换后的二进制数。把以上函数写成: outbinary(int a){ int d;d=a%2;if(a![KG-*4/5]=0){ outbinary(a/2);printf(″%d″,d);} } 这就达到了后得的数先输出的目的。11.13【分析与解答】 (1)在主函数中输入n的值。 (2)这是一个累加的过程,若从n开始逐个累加,而每次的加数比前一个减1,可用以下函数实现: sum(int n){ return n+sum(n-1);}(3)递归算法的主要一条是需要有递归结束条件,否则递归会无限进行。由题目可知,当累加项为0时,累加应当结束。所以在函数中应该添加条件语句: sum(int n){ if(n![KG-*4/5]=0)return n+sum(n-1);} 11.14 【分析与解答】 以上F(n)函数已经给出了明确的递归算法,所以只要把它用C语言来表达就可以了: f(int n){ if(n==0 || n==1)return 1;return(f(n-1)+f(n-2));} + 第十二章 C语言中用户标识符的作用域和存储类习题分析与解答 一、选择题 12.1 【参考答案】 B)12.2 【参考答案】 B)12.3 【参考答案】 A)12.4 【参考答案】 C)12.5 【参考答案】 D)12.6 【参考答案】 B)12.7 【参考答案】 A)12.8 【参考答案】 D) 二、填空题 12.9【参考答案】 2,5,1,2,3,-2 12.10【参考答案】 2468 第十三章 编译预处理和动态存储分配习题分析与解答 一、选择题 13.1 【参考答案】 A)13.2 【参考答案】 C)13.3 【参考答案】 B)13.4 【参考答案】 C)13.5 【参考答案】 D)13.6 【参考答案】 D)13.7 【参考答案】 D) 二、填空题 13.8 【参考答案】 ar=9 ar=9 ar=11 13.9 【参考答案】 [1]int* [2]s [3]*b 三、编程题 13.10【分析与解答】(1)此命令行如下: #define MYALPHA(a)(((a)>=′A′&&(a)<=′Z′)||((a)>=′a′&&(a)<=′z′))(2)可用以下程序段来验证,此处s中存放了字符串,num中统计大、小写字母的个数: for(i=0;i #define SWAP(t,x,y){t w;w=x;x=y;y=w;}(2)若有以下程序段: double a=99.99,b=11.11;SWAP(double,a,b);则SWAP(double,a,b)展开后有: { double w;w=a;a=b;b=w;};此处w是一个局部变量,它的作为域仅在复合语句内部,与程序中任何与其同名的变量无关。(3)请读者自编程序,调用以上带参的宏,对各种类型数据进行交换。参数t对应的应当是类型名。 13.12 【分析与解答】 (1)请编写一个swap函数,用于对两个整型变量中的值进行对调。(2)定义3个基类型为int的指针变量p1、p2和p3。 (3)3次调用malloc函数,分别使p1、p2和p3指向三个动态分配的存储单元。程序准备把最小数放在p1所指动态存储单元中,把最大数放在p3所指动态存储单元中。(4)调用scanf函数给p1、p2和p3所指的3个动态分配存储单元赋值。(5)以下语句输出p1、p2和p3所指的动态存储单元中的值: printf(″\[KG-*3]n*[KG-*3]p1=%d p2=%d p3=%d\[KG-*3]n\[KG-*3]n″,*[KG-*3]p1,*[KG-*3]p2,*[KG-*3]p3);(6)如果p2所指的动态存储单元中的值小于p1所指的动态存储单元中的值,则调用swap函数把这两个存储单元中的值进行交换,使大数放入p2所指的动态存储单元中,小数放入p1所指动态存储单元中: if(*[KG-*3]p2<*[KG-*3]p1)swap(p1,p2);(7)如果p3所指的动态存储单元中的值小于p1所指的动态存储单元中的值,则调用swap函数把这两个存储单元中的值进行交换,使小数放入p1所指的动态存储单元中。(8)如果p3所指的动态存储单元中的值小于p2所指的动态存储单元中的值,则调用swap函数把这两个存储单元中的值进行交换,使小数放入p2所指的动态存储单元中。 (9)以上步骤已把最小的数放入p1所指的动态存储单元中,最大的数放入p3所指的动态存储单元中。输出这3个指针所指的存储单元中的值,以便验证结果是否正确。(10)本题的算法应该已很熟悉,只是要求用动态存储单元来代替普通的变量。 第十四章 结构体、共用体和用户定义类型习题分析与解答 一、选择题 14.1 【参考答案】 D)14.2 【参考答案】 D)14.3 【参考答案】 D)14.4 【参考答案】 A)14.5 【参考答案】 B)14.6 【参考答案】 C)14.7 【参考答案】 C)14.8 【参考答案】 B)为52 二、填空题 14.9 【参考答案】 struct link *next 14.10 【参考答案】 [1] p->next [2] m>p->data(或p->data [1](struct list *)[2] struct list [3](struct list *)[4] struct list [5] h 三、编程题 14.12 【分析与解答】 (1)为了便于调试程序,定义宏名N来表示30: #define N 30(2)主函数中定义一个名为st的struct stud类型的结构体数组,用以存放学生数据: struct stud st[N];(3)readrec函数的首部可以写成: void readrec(struct stud *[KG-*3]ps)形参指针指向实参数组st的起始地址。在函数中可以用ps[i].num、ps[i].s[j]、ps[i].ave等这样的形式引用主函数st数组元素中的成员,也可用(ps+i)->num或(*(ps+i)).num等形式引用主函数st数组元素中的成员,因为在函数中,形参ps是一个指针变量。(4)在readrec函数中,可以在一个for循环中输入结构体数组每个元素中的数据: for(i=0;i 在循环体中,可用gets(ps[i].num);gets(ps[i].name);输入学生的学号和姓名。可用一个内嵌的for循环输入每个学生的四项成绩并同时累加成绩并求平均分: for(j=0;j<4;j[KG-*3]+[KG-*3]+){ scanf(″%d″,&ps[i].s[j]);ps[i].ave+[KG-*3]=ps[i].s[j]/4.0;} 在scanf语句中,输入项是指针(ps+i)所指成员s[j]数组元素的地址,因此输入项也可以写成:ps[i].s+j。另外要注意,在进入此for循环前,应当给ps[i].ave赋0值。 注意:在执行scanf语句读入成绩时,最后必定要按一个ENTER键,以便结束输入,但此回车符并没有被当作成绩读入,而是留在输入缓冲区内;若下一个输入项是数值数据时,并不会影响输入,而在此处,下一次又将去调用gets函数来给num输入一个字符串,于是,回车 符被自动当作字符串的结束符读入,num中被赋“空”串,程序接着要求输入name。因此在退出以上控制变量为j的for循环后,需要有一个getchar()语句,以便“读入”一个字符,不使回车符留在输入缓冲区内。这虽是一个细节,但它能使输入正确进行。(5)writerec函数的首部可以写成: void writerec(struct stud *[KG-*3]ps)(6)在writerec函数中,可以在一个for循环中输出结构体数组每个元素中的数据: for(i=0;i 可以用以下语句输出学号和姓名: printf(″%s %s″,(ps+i)->num,(*(ps+i)).name);当然输出项也可以写成:ps[i].num、ps[i].name。和在readrec函数中一样,用一个内嵌的for循环输出四项成绩,最后输出ps[i].ave。 (7)在readrec函数中请添加输入提示,以便正确输入;在writerec函数中请添加有关的输出文字,使输出内容更清晰。 (8)请自己编写主函数,写出定义语句和调用语句。 (9)总结:本题的算法十分简单,仅是输入和输出,但要求能够掌握结构体数组在函数之间的数据传递,要求对结构体变量中成员能正确引用。在调试程序时,为了便于输入,可把define行改为: #define N 2 这样只需输入两组数据,也同样可以对程序的正确性进行验证。14.13 【分析与解答】 (1)本题所要求编写的函数可参考本章习题14.10。 (2)为了能对链表进行操作,必须建立链表,建立链表的函数可参考本章习题14.11。输出链表可参考教材第四章例14.7。 (3)本题第二个函数要求返回的是最大值所在结点的地址,若此函数名为maxadd,函数首部可以如下: struct node * maxadd(struct node *head)此处,struct node是链表结点的类型。函数的基本算法和习题14.10基本相同,只是需要另定义一个基类型为struct node的指针,假定此指针名为pmax,则每次当把最大值放入m时,同时也把此结点的地址放入pmax中,最后返回pmax即可。基本的程序段如下: p=head->next;m=p->data;pmax=p;for(p=p->next;p;p=p->next)if(m data){ m=p->data;pmax=p;}(4)在主函数中也需要定义一个基类型为struct node的指针,若定义该指针名为:maxnode,则应当把函数maxadd的返回值赋给它:maxnode=maxadd(head);,此处head指向链表的头结点。可用:printf(″%d\[KG-*3]n″,maxnode->data);输出maxnode所指结点中的数据域,以验证maxnode是否指向链表中的最大值所在的结点。 (5)总结:函数的类型可以是指向结构体的指针类型,也可以是结构体类型。读者也可编写一个函数,把最大值所在的结点放在一个结构体变量中作为函数值返回。 第十五章 位运算习题分析与解答 一、选择题 15.1 【参考答案】 D)15.2 【参考答案】 A) 15.3 【参考答案】 B)15.4 【参考答案】 A) 二、填空题 15.5 【参考答案】 11110000; 15.6 【参考答案】 a=a&0; 15.7 【参考答案】 a=a|07777; 15.8 【参考答案】 a=a|0177400; 15.9 【参考答案】 a=012500>>2; 15.10 【参考答案】 ch=ch|32; 第十六章 文件习题分析与解答 一、选择题 16.1 【参考答案】 B)16.2 【参考答案】 C) 二、填空题 16.3 【参考答案】 [1] 3 [2]!feof(f1)[3] f2 [4] fclose(f1)[5] fclose(f2)16.4 【参考答案】 [1] fopen(fname,″w″)[2] ch 16.5 【参考答案】 [1] ″r″ [2](!feof(fp))[3] fgetc(fp)16.6 【参考答案】 AAAABBBBCCCC 三、编程题 16.7 【分析与解答】 (1)因为指定为10个字符串,并假定每个字符串不会超过20个字符,为方便起见,在程序的前面定义以下命令行: #define N 10 #define M 22(2)假定字符串输出到名为myfile.dat的文件中;程序中字符串放在名为s的字符数组中。(3)按照题义程序应有以下步骤: ① 首先为“写”而打开文件: fp=fopen(″myfile.dat″,″w″);② 从终端输入字符串,输入一个字符串,就立即把它输出到文件中,因为有N个字符串,因此需要放在循环中来完成: for(i=1;i<[KG-*3]=N;i[KG-*3]+[KG-*3]+){ printf(″Enter a string: ″);gets(s);fputs(s,fp);fputc(′\[KG-*3]n′,fp);} 函数fputs(s,fp)把刚从终端读入的字符串s输出到fp所指的文件中。请注意函数fputs(s,fp)的输出特点:在输出时它将只输出字符串中的字符而不输出字符串的结束标志到文件中,因此在文件中,连续输出的字符串之间将头尾相接,在文件中储存了一个接一个的字符,分不清哪是哪个字符串,其结果就使得不再可能从其中读入各个字符串了。为了分清各个字符串,因此在每输出一个字符串时,就接着输出一个′\[KG-*3]n′符,以区分各字符串,在此由fputc(′\[KG-*3]n′,fp);来完成。③ 关闭因“写”而打开的文件: fclose(fp);④ 为“读”而打开文件: fp=fopen(″myfile.dat″,″r″); ⑤ 从文件中输入字符串并把刚读入的字符串输出到终端屏幕: fgets(s,M-1,fp);while(!feof(fp)){ c=s[strlen(s)-1];if(c==′\[KG-*3]n′)s[strlen(s)-1]=0;puts(s);fgets(s,M-1,fp);} fgets(s,M-1,fp)从fp所指文件中输入M-1个字符串放入s的地址中;如果在未读满M-1个字符之前读到了一个换行符,则结束本次操作,系统在字符串最后自动加入′\0′。注意,如果未读满M-1个字符,这时已把换行符读入,并作为字符串最后一个字符(在′\0′之前)。在此,先判断s[strlen(s)-1]是否为′\[KG-*3]n′,若是,则用语句:s[strlen(s)-1]=0;来消除此换行符,把字符串结束标志前移了一个位置,strlen(s)求出字符串的长度,strlen(s)-1是最后一个字符的下标。然后用puts(s);进行输出。fgets(s,M-1,fp);作为循环体内最后的语句,当读到文件的结束标志时,函数feof(fp)的值为1,循环立即结束。⑥ 关闭文件: (4)请读者自己完成其他相关的语句和定义。 (5)总结:在用fgets和fputs函数进行输入和输出时,请注意它们的特点,以便使字符串的输入和输出正确进行。16.8【分析与解答】 (1)按题意程序需要两次把数据输出到文件中,第一次是把从键盘输入的数据输出到文件中,第二次是把修改过的数据再次输出到文件中。为此编写一个函数来完成此项任务,以避免重复编码。同理,程序需要两次从文件中输入数据,因此也用一个函数来完成此任务。另外程序需要两次把从文件输入的数据输出到屏幕上,因此也用一个函数来完成。(2)因为指定为10个双精度数,为方便起见,在程序的前面定义以下命令行: #define N 10(3)为了便于操作,无论是输入的数据还是输出的数据,程序都把它们放在一个数组中。(4)若程序把输出的数据放在mybin.dat文件中,在函数binput中把数据输出到mybin.dat文件,binput函数的首部应是: binput(double *a)形参a是一个基类型为double的指针,它接受存放数据的实参数组的首地址。函数中需要包含以下步骤: ① 打开输出文件: fp=fopen(″mybin.dat″,″wb″);fp是文件指针,mybin.dat是输出文件名,″wb″规定此次是为“写”而打开一个二进制文件。② 输出数据到二进制文件中: for(i=0;i ① 打开输入文件: fp=fopen(″mybin.dat″,″rb″);fp是文件指针,mybin.dat是输入文件名,″rb″规定此次是为“读”而打开一个二进制文件。② 从二进制文件中输入数据: fread(a,sizeof(double),N,fp);此语句的含义是:从fp所指文件中输入N个sizeof(double)字节的数据,放入a所指地址开始的存储区中。因此,此语句一次就从文件中读入N个双精度数,并把它们放入了a所指的数组中。 ③ 输入结束,关闭文件: fclose(fp);(6)程序若用名为pri的函数把数组中的数据输出到屏幕上,pri函数的首部应是: pri(double *a)此函数十分简单,请读者自己编写。 (7)主函数中只需按本题的要求调用所需函数即可: main(){ double s[N]; int i;printf(″\[KG-*3]nEnter 10 double numbers: ″);for(i=0;i (9)总结:在所给的程序中,binput函数和binread函数中介绍了对fwrite和fread的不同调用方式,对于fwrite和fread函数,这两种方式都是可用的。 全国计算机二级C语言考试上机题型总汇 (一)关于“******”问题 1、将字符串中的前导*号全部删除,中间和后面的*号不删除。void fun(char *a){ char *p=a;while(*p= =’*’)p++;for(;*p!=’ ’;p++,a++)*a=*p;*a=’ ’;} 2、只删中间* int i;for(i=0;a[i]= =’*’;i++)for(;h 3、只删尾* while(*a!=’ ’)a++;a--;while(*a= =’*’)a--;*(a+1)=’ ’; 4、只留前* int i , j=0;for(i=0;a=’*’;i++);j=i;for(;a;i++)if(a!=’*’)a[j++]=a[i];a[j]=’ ’; 5、只留中间* int i,j=0;for(i=h;i第二篇:《全国计算机等级考试二级教程C语言程序设计》
第三篇:计算机等级《二级C语言程序设计》押题卷
第四篇:《全国计算机等级考试二级教程——C语言程序设计》课后习题详细答案
第五篇:计算机二级C语言上机题型总结