目录

  • 前言
  • 第1章 C语言概述
  • 第2章 数据类型及其运算
  • 第3章 顺序结构程序设计
  • 第4章 选择结构程序设计
  • 第5章 循环结构程序设计
  • 第6章 数组与指针
  • 第7章 函数与指针
  • 第8章 结构体与共用体
  • 第9章 文件
  • 第10章 图形与动画

推荐阅读:http://t.csdn.cn/nQfIY

习题解析与答案

前言

《C程序设计(第五版》是由谭浩强编著,2017年清华大学出版社出版的“十二五”普通高等教育本科国家级规划教材、北京市高等教育精品立项项目教材、中国高等院校计算机基础教育课程体系规划教材。该教材是既可作为高等学校各专业的正式教材,也适合读者自学。
该教材共10章,主要内容包括:设计和C语言,算法——程序的灵魂,最简单的C程序设计——顺序程序设计,选择结构程序设计等。

特此整理一份习题解析,以便复习之用

第1章 C语言概述

一. 简答题

1.概述C语言的主要特点。

【解答】

(1)语言简洁、紧凑,使用方便、灵活。

(2)数据类型丰富,表达能力强。

(3)运算符多样。C语言中的运算符包含的范围非常广泛。

(4)具有结构化的控制语句。如if…else语句、while语句、do while语句、switch语句、for语句。

(5)允许直接访问物理地址。C语言中含有的位和指针运算,能够直接对内存地址进行访问操作。

(6)所生成的目标代码质量高,可移植性好。

2.构成C语言程序的基本单位是什么?它由哪几部分组成?

【解答】函数是构成C语言程序的基本单位。一个完整的C程序一般由文件包含、宏定义、函数说明、变量和一个或若干个函数组成。

3.C语言程序的运行一般要经过哪几个步骤?

【解答】(1)编辑;(2)编译;(3)连接,生成EXE文件;(4)执行。

二.运行程序写结果

1.输入下面程序并运行。

main(){int a1,a2,x;a1=100;a2=50;x=a1-a2;printf(″x=%d\\n″,x);

【解答】运行结果为:

x=50

2.输入下面程序并运行。

main(){int a1,a2,x;a1=10;a2=20;x=a1\*a2;printf(″a1=%d,a2=%d\\n″,a1,a2);printf(″x=%d\\n″,x);

【解答】运行结果为:a1=10,a2=20

x=200

3.输入下面程序并运行。

#include \main(){printf("\*\*\*\*\*\*\\n");printf(" \*\*\*\*\*\\n");printf(" \*\*\*\*\\n");printf(" \*\*\*\\n");printf(" \*\*\\n");printf(" \*\\n");}

【解答】运行结果为:

******
*****
****
***
**
*

思考:可以修改程序,使之输出平行四边形,等腰三角形等图形。

三.编程题

1.参照本章例题,编写一个C程序,用于显示如下信息:

*************************
I love C programs!
*************************

【分析与提示】

①要有文件包含语句#include 。C语言中没有数据的输入、输出等功能,数据的输入、输出都是通过调用系统提供的库函数scanf和printf等来实现的。这些函数的说明都包括在stdio.h文件中。

②main是主函数的名称。用{}括起来的内容是函数体,函数体由若干条语句组成,这是计算机要执行的部分,每条语句以分号“;”结束。

③注意显示的信息有三行,所以要用到换行符“\n”。

参考代码:

#include \ main(){printf("\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\\n");printf(" I love C programs! \\n");printf("\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\\n");}

第2章 数据类型及其运算

一.简答题

1.C语言中的数据类型主要有哪几类?

【解答】

短整型(short int )
整型 整 型 (int)
长整型(long int )
基本类型 字符型 (char) 单精度(float)
实型(浮点型)
双精度(double)
枚举类型(enum)
数组类型
构造类型 结构体类型 (struct)
共用体类型(union)
指针类型
空类型(void)

  1. 字符常量与字符串常量有什么区别?

【解答】

字符常量用单括号括起,字符串常量用双括号括起;字符常量存储时占1个字节,字符串常量存储时除了n个字符外,还有系统加上的字符串终止符\0,所以字符串常量存储时占n+1个字节。

  1. C语言中的常量包括哪几类?各自是如何构成的?

【解答】

C语言中的常量是一些其值预先定的量,并且在程序执行过程中其值不再发生变化。常量的分类遵循基本数据类型分类原则,C语言编译系统自动将其存放在于类型相应的内存单元中。其类别包含整形常量、浮点常量、字符常量、字符串常量和枚举常量。整形常量又分为十进制整形常量、八进制整形常量、十六进制整形常量。浮点常量分成十进制形式和指数形式。C语言中的,字符常量是用单括号括起来的一个字符或是字符序列,而字符串常量是用一对双括号括起来的零个或者多个字符组成的序列。

  1. 简述指针、变量的指针、变量的值、指针变量与指针变量的值的含义是什么?

【解答】

C语言中将地址又称为“指针”。一个变量所分配的内存空间首字节地址,称为该变量的指针(地址),变量的值就被放入所分配的地址单元中。地址一旦被分配,就不会再改变,所以,指针是一个常量。既然是常量就可以把它赋给一个变量。用来存放指针的变量,被称为指针变量。一个指针变量的值是变量的地址,一个指针变量可以被赋予不同的指针值。

  1. 下面哪些是不合法的常量?说明不合法的理由。

123,3.1415926,0892,’M’,’\n’,0xabc,0.618E-6,”Morning”,3.8e-3.14

【解答】非法常量有:

0892——含有非八进制数字8和9
3.8e-3.14——非法指数形式浮点常量:规定e后面的指数必须为整数。

6.下面对变量定义的语句哪些不正确?为什么?请改正。

(1) char c1,int a2; (2) INT a,b; FLOAT x,y;(3) a,b:char;

(4) char if; (5) int a,b (6) Int a️c;

(7) int a,x; float x,y;

【解答】

(1) char c1,int a2;
错误。定义不同类型的变量时,应用分号彼此分开。
改正为:char c1; int a2;

(2) INT a,b; FLOAT x,y;

错误。C语言中表示类型名的关键字必须小写。

改正为:int a,b; float x,y;

(3) a,b:char;

错误。C语言中变量定义格式为:类型名 变量名;

改正为: char a,b;

(4) char if;

错误。变量名不能与C语言的关键字重名。

改正为:char f1;

(5) int a,b

错误。变量定义以语句形式出现,应以分号结尾。

改正为:int a,b;

(6) Int a️c;

错误。类型名不能有大写字母,相同类型名之间用逗号分隔。

改正为:int a,b,c;

(7) int a,x; float x,y;

错误。在同一程序位置上,同一变量名不能重复定义充当两个不同的变量。

改正为:int a,x; float x1,y;

  1. 下述字符串常量的长度是多少?在内存中存储时各自占用的单元数又是多少?

(1) “Hello!” (2) “ABC\n\\TH\064\?” (3) “\xAB*\765+123=?”

【解答】

(1)“Hello!” 字符串长度为6,占用内存字节数为7。

(2)“ABC\n\\TH\064\?” 字符串长度为9,占用内存字节数为10。因为其中\n \\ \064\?各自只占一个字符的位置。

(3) “\xAB*\765+123=?” 该字符串不是合法的,因为\765表示的值太大,超出合法的ASCII字符集的范围。

二.运行程序写结果

1.以下程序的执行结果是____。

main(){int i,j;i=15printf(%d,%d”, i++,i--)}

【解答】14,15

2.以下程序的执行结果是 。

main(){int a=20,b=10,c,\*p1,\*p2;p1=&a;p2=&b;c=(-\*p1)/(\*p2)+6;printf("a=%d,b=%d\\n",a,b);printf("\*p1=%d,\*p2=%d\\n",\*p1,\*p2);printf("c=%d\\n",c);}

【分析与提示】

p1 a
P2 b`

【解答】

a=20,b=10
*p1=20,*p2=10
c=4

3.以下程序的执行结果是 。

#include \main(){char a=’G’,b=’o’,c=’o’,d=’d’;a=a+32;b=b-6;c=c+3;d=d+8;printf("%c%c%c%c\\n",a,b,c,d);}

【分析与提示】

从ASCII代码表可以看出,字符“G”、“o”、“o”、“d”的ASCII代码值为71、111、101,因此,’G’+32、’o’-6、’o’+3、’d’+8的值分别是103、105、114、108,它们所对应的字符分别是“g”、“i”、“r”、“l”。

常用结论:

(1)在C语言中,字符数据可以按其ASCII代码值参加整数运算。由于英文字母在ASCII代码表中是按顺序排列的,所以在计算’o’+3代表的字母时,可从字符’o’其顺序向后取3个字母,该字母是“r”。

(2)从ASCII代码表可以看出“小写字母”-“对应大写字母”的结果是32,因此可推算出如下等式:大写字母的ASCII值+32=对应小写字母的ASCII值;小写字母的ASCII值-32=对应大写字母的ASCII值。

【解答】girl

4.以下程序的执行结果是 。

#include \main(){int x;x=-3+4\*5-6;printf("x1=%d\\n",x);x=3+4%5-6;printf("x2=%d\\n",x);x=-3\*4%-6;printf("x3=%d\\n",x);}

【分析与提示】

x1=11(4*5是20,-3+20是17,17-6等于11)
x2=1(4%5等于4,3+4等于7,7-6等于1)
x3=0(-3*4等于-12,-12%-6等于0)

【解答】

x1=11
x2=1
x3=0

5.以下程序的执行结果是 。

#include \main(){printf("%d\\n",NULL);printf("%d,%c\\n",49,49);printf("%d,%c,%o\\n",48+10,48+10,48+10);}

【分析与提示】

0(NULL的ASCII码值是0)
49,1(数字1的ASCII码值是49)
58,:,72(48+10等于58,正好是“:”的ASCII码值,八进制表示是72)

【解答】
0

49,1

58,:,72

三、改错题

  1. 请修改下列程序,使其能够通过编译。
 #include \Void Main(){int a=6;b=8;int c;c=a\*b;printf(%d’,c);}
【答案】错误的地方有3处:(1)第2行关键字应该小写;(2)定义b时前面应该用逗号;(3)打印语句的格式应该用双引号括起来。正确的程序如下:\#include \void main(){int a=6,b=8;int c;c=a\*b;printf("%d",c);}
  1. 请修改下列程序,使其能够正确运行。
 #include \void main();{float f=7.12;char c=”c”;printf(%d\\n”,int(f%3));printf(%c”,c);}
【答案】错误的地方有3处:(1)第2行main();不应该有分号;(2)定义char c=”c”;时,字符常量应该用单引号;(3)打印语句printf(“%d\\n”,int(f%3));的格式有错,应该在f前的int用括号括起来,因为实型数据不能执行取余运算。正确的程序如下:
#include \void main(){ float f=7.12;char c='c';printf("%d\\n",((int)f %3));printf("%c",c);}

第3章 顺序结构程序设计

一. 简答题

1.程序有哪三种基本结构?

【解答】程序的三种基本结构为:顺序结构、选择结构和循环结构。

2.C语言的语句有哪几类?表达式语句与表达式有什么不同?

【解答】C语句可分为以下五类:表达式语句、函数调用语句、控制语句、复合语句和空语句。其中表达式语句与表达式的区别在于表达式语句是表达式加上“;”组成。

二、填空题

1.符号’&’ 是_______运算符,&a是指_______。

2.C语言中的空语句就是_______。

3.Scanf函数中的“格式字符”后面应该是_______,而不应该是______。

4.若想输出字符%,则应该在“格式字符”的字符串中用_____表示。

5.int x=7;执行x+=x- =x+x;后x的值是_______。

6.int a=10,b=20;a+=b;b=a-b;a- =b; 的功能是_______。

答案:1.地址、变量a的内存地址。

2.一个分号。

3.变量地址,变量名。

4. 连续2个%号。

5. -14

6.交换 变量a,b的值,打印出a=20,b=10。

三.运行程序写结果

1.以下程序的执行结果是 。

#include \main(){double d=3.2;int x,y;x=1.2;y=(x+3.8)/5.0;printf("%d\\n",d\*y);}

【解答】0

2.以下程序的执行结果是 。

main(){double d;float f;long l;int i;i=f=l=d=20/3;printf("%d %ld %f %f\\n",i,l,f,d);}

【解答】6 6 6.000000 6.000000

3.以下程序的执行结果是 。

main(){int k=17;printf("%d,%o,%x\\n",k,k,k);}

【解答】17,21,11

4.以下程序的执行结果是 。

#include \main(){char a,b,c,d;a='A',b='B',c='C',d='D';printf("%1c\\n",a);printf("%2c\\n",b);printf("%3c\\n",c);printf("%4c\\n",d);}

【分析与提示】可以用%c格式输出的,也可以用%d格式输出,所以与%md近似,m指出了要输出数据的宽度。若数据位数小于m,则左端补空格,若数据位数大于m,则按实际位数输出。

【解答】A

B

C

D

5.以下程序的执行结果是 。

#include \main(){char c1,c2;scanf("%c%c",&c1,&c2);printf("c1=%c,c2=%c,c3=%d,c4=%d",c1++,--c2,c1,c2);}

【解答】运行输入:AB

运行结果为:c1=A,c2=A,c3=65,c4=66

6.以下程序的执行结果是 。

#include \main(){char c1,c2;scanf("%c,%c",&c1,&c2);\++c1;\--c2;printf("c1=%c,c2=%c\\n",c1,c2);}

【分析与提示】例如当输入B,C,B,C的ASCII码值为66,67,执行++c1; –c2;后,c1为66+1变成67即C,c2为67-1变成66即B。

【解答】运行输入:B,C,运行结果为:c1=C,c2=B

7.以下程序的执行结果是 。

main(){char ch='a';int a=98;unsigned b=1000;long c=123456789;float x=3.14;double y=1.2345678;printf("(1)a=%d,a=%c,ch=%d,ch=%c\\n",a,a,ch,ch);printf("(2)b=%u\\n",b);printf("(3)c=%ld\\n",c);printf("(4)x=%f,y=%f\\n",x,y);printf("(5)x=%e,y=%e\\n",x,y);printf("(6)y=%-10.2f\\n",y);}

【解答】(1)a=98,a=b,ch=97,ch=a

(2)b=1000

(3)c=123456789

(4)x=3.140000, y=1.234568

(5)x=3.14000e+00,y=1.23457e+00

(6)y=1.23

8.以下程序的执行结果是 。

#include\main(){int a,b;float x;scanf("%d,%d",&a,&b);x=a/b;printf("\\nx=%f\\n",x);}

【解答】运行输入:2,2,运行结果为:1.000000

9.当输入12345,a时,给出程序的运行结果,执行结果是 。

#include\main(){int a;char c;scanf("%3d,%c",&a,&c);printf("\\n%d,%d\\n",a,c);}

【分析与提示】%md,m指出了要输出数据的宽度。若数据位数小于m,则左端补空格,若数据位数大于m,则按实际位数输出。a的ASCII码值是97。

【解答】12345,97

10.分析下面程序,在键盘上输入数据 才能使得变量a=10,b=20,c1=’A’,c2=’a’,x=1.5,y=-3.75,z=67.8。

程序如下:

#include\main(){int a,b;float x,y,z;char c1,c2;scanf("%5d%5d%c%c%f%f%\*f,%f",&a,&b,&c1,&c2,&x,&y,&z);printf("a=%d,b=%d,c1=%c,c2=%c,x=%f,y=%f,z=%f",a,b,c1,c2,x,y,z);}

【分析与提示】按%5 d格式输入a与b的值时,要先键入三个空格,然后再键入10与20。%*f是用来禁止赋值的。在输入时,对应%*f位置可以随意输入一个数(我们输入1.5,该数不会赋值给任何变量的)。

【解答】运行输入:└┘└┘└┘10└┘└┘└┘20Aa1.5└┘-3.75└┘1.5,67.8

11.一个程序中,使用了多个scanf函数输入数据,用a=3,b=7,x=8.5,y=71.82,c1=’A’,c2=’a’ 输入到每个变量,应该如何输入数据?

main()

{

int a,b;

float x,y;

char c1,c2;

scanf(“a=%d,b=%d”,&a,&b);

scanf(” x= %f,y=%e”,&x,&y);

scanf(” c1= %cc2=%c”,&c1,&c2);

printf(“a=%d,b=%d,x=%f,y=%f,c1=%c,c2=%c\n”,a,b, x,y,c1,c2);

}

【分析与提示】在使用多个scanf函数输入数据时,第一个输入行末尾输入的回车被第二个scanf函数吸收,因此在第二、三个scanf函数的双引号后放置一个空格以抵消上行输入的回车键。若没有一个空格,则按上面输入的数据会出错。

【解答】运行输入:a=3, b=4

X=8, y=71.82

C1=AC2=a

运行结果:a=3,b=7,x=8.500000,y=71.820000,c1=A,c2=a

四.编程题

1.由键盘输入1个字母,输出其ASCII码值。

【分析与提示】将一个字符常数赋给一个字符变量,并不是把该字符本身放到内存单元中去,而是将该字符的ASCII代码放到内存单元中,因此,字符型数据也可以像整型数据那样使用,可以用来表示一些特定范围内的整数。所以int型与char型变量的值可以互换,分别用%c和%d不同格式输出就行了。

但是注意这种转换是有条件的。因为,char变量在内存占一个字节,而int整型变量占2个字节。当int型高位字节是0时,char与 int可以互换;若不是0,则不可以互换。例如,用%c格式输出时,取低位字节,高位字节被舍弃。

参考代码:

#include “stdio.h”

main()

{

char ch;

ch=getchar();

printf(“%c,%d”,ch,ch);

}

【解答】运行输入:B

运行结果:B,66

2.从键盘上输入一个大写字母,把它转换成小写字母,然后显示出来。

【分析与提示】大写字母转换小写时ASCII码值+32,相反的,小写字母转换成大写字母时ASCII码值-32。

参考代码:

#include

main()

{

char x1,x2;

printf(“x1=?\n”);

scanf(“%c”,&x1);

x2=x1+32;

printf(“%c,%c\n”,x1,x2);

}

【解答】运行输入:A

运行结果:A,a

3.从键盘上输入两个实型数,求两数的和、差、积,输出结果时要求小数部分占两位。

【提示】结果要求保留2位小数,所以输出的结果格式为%.2f。

main()

{

float x,y,a,b,c;

printf(“please input x,y:”);

scanf(“%f,%f”,&x,&y);

a=x+y;

b=x-y;

c=x*y;

printf(“x=%f,y=%f\n”,x,y);

printf(“x+y=%.2f\nx-y=%.2f\nx*y=%.2f\n”,a,b,c);

}

【解答】

运行输入:please input x,y:10,20

运行结果:x=10.000000,y=20.000000

x+y=30.00

x-y=-10.00

x*y=200.00

4.编写一个程序,求出给定半径r的圆以及内正n边形的面积,并且输出计算结果。r和n的值由用户输入。

【分析与提示】由数学知识得到: 半径为r圆的面积,半径为r圆的内接正n边形的面积,其中

处理步骤:提示信息,接收参数值;计算圆的面积; 计算正n边形的面积;输出结果。

参考代码:

#include

#include

#define PI 3.14

main()

{

int n;

float r,s,area;

printf(“Please input the radius and the N.:\n”);

scanf(“%f%d”,&r,&n);

s=PI*r*r;

area=(n*r*r*sin(2*PI/n))/2.0;

printf(“S=%.2f\tA=%.2f\n”,s,area);

return(0);

}

运行结果如下:

Please inout the radius and the N.;

  1. 5

    S=3.14 A=2.38

5.已知华氏温度与摄氏温度之间的转换公式是:, 编写一个程序,将用户输入的华氏温度转换成摄氏温度,并予以输出。

【分析与提示】首先要定义输入输出温度为浮点型,且5/9两数相除结果为整数,5/9的值为0,故不能写成5/9,而应写成(5.0/9.0)*(f-32)。结果要求保留2位小数,所以输出的结果格式为%5.2f。

参考代码:

#include

main()

{

int f;

float c;

printf(“\nplease input the F:”);

scanf(“%d”,&f);

c=5.0/9*(f-32); /*不能写成5/9,两数相除结果为整数,5/9的值为0*/

printf(“the C.temperature is: %.2f”,c);

return(0);

}

【解答】运行结果如下:

please input the F: 75

the C.te,[erature is: 23.89

6.由键盘输入5个学生的计算机成绩,计算他们的平均分并保留2位小数。

【分析与提示】方法与上题类似,同样是保留两位有效数字%6.2f。

参考代码:

main()

{

int a,b,c,d,e;

float total,aver;

printf(“Plese input 5 students’ scores:\n”);

scanf(“%d,%d,%d,%d,%d”,&a,&b,&c,&d,&e);

total=a+b+c+d+e;

aver=total/5.0;

printf(“Average:%6.2f\n”,aver);

}

【解答】运行输入:80,93,75,68,87

运行结果:Average:80.60

7.编写将输入的英里转换为公里,每英里等于5380英尺,每英尺等于12英寸,每英寸等于2. 54厘米,每公里等于100 000厘米。

main()

{

double mile,k;

printf(“enter mile:”);

scanf(“%lf”,&mile);

k=mile*5380*12*2.54/100000;

printf(“ %lf mile is %lf kilometer\n”,mile,k);

}

【解答】运行:enter mile:2↙

2.000000 mile is 3.279648 kilometer

第4章 选择结构程序设计

4.1 习题

一.填空题

1.已知a=3,b=4,c=5。则逻辑表达式a+b>c&&b= =c的值为 ,!(a>b)&&c||1的值为 ,!(a+b)+c-1&&b+c/2的值为 。

【分析与提示】本题考查运算符的优先级别。

【解答】0 ; 1 ; 1

二、运行程序写结果

1.下列程序运行的运行结果为 。

#include

main()

{

int a=3,b=8,c=9,d=2,e=4;

int min;

min=(a<b)? a:b;

min=(min<c)? min:c;

min=(min<d)? min:d;

min=(min<e)? min:e;

printf(“Min is%d\n”,min);

【分析与提示】本题程序的功能为:找出a,b,c,d,e中最小的值并输出。

【解答】Min is 2

2.若输入3,4,下列程序运行的运行结果为 ;若输入4,3,下列程序运行的运行结果为 。

#include

main()

{

int a,b,c;

printf(”Input a,b: “);

scanf(”%d,%d”,&a,&b);

if(a>=b)

{c=a*b; printf(”%d*%d=%d\n”,a,b,c);}

else

{c=a/b; printf(”%d/%d=%d\n”,a,b,c);}

【分析与提示】本题程序的功能为:从键盘输入变量a,b,计算c的值(若a>=b,则c=a*b,若a<b则c=a/b),并输出a,b,c的值。

【解答】3/4=0 ; 4*3=12

3.下列程序运行的运行结果为 。

#include

main()

int x=1,y=0,a=0,b=0;

switch(x)

case 1:

switch(y)

{case 0: a++; break;

case 1: b++; break;

case 2: a++; b++; break;

printf(“a=%d,b=%d\n”,a,b);

【分析与提示】本题中case 1:后面是一个switch语句,执行完该语句后,直接执行case 2:后面的语句。

【解答】a=2,b=1

三.编程题

1.输入一个字母,若为小写,则把它变成大写输出。

【分析与提示】小写字母的ASCII码值与其对应的大写字母的ASCII码值相差32。

参考代码:

main( )

{

char c;

printf(“请输入一个字母\n”) ;

scanf(“%c”, &c);

if(c>=’a’&&c<=’z’)

c=c-32;

printf(“%c\n”,c) ;

}

2. 企业发放的奖金根据利润提成。利润(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,求应发放奖金总数?

【分析与提示】请利用数轴来分界,定位。注意定义时需把奖金定义成长整型。
参考代码:

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;

else if(i<=200000)

bonus=bonus1+(i-100000)*0.075;

else if(i<=400000)

bonus=bonus2+(i-200000)*0.05;

else if(i<=600000)

bonus=bonus4+(i-400000)*0.03;

else if(i<=1000000)

bonus=bonus6+(i-600000)*0.015;

else

bonus=bonus10+(i-1000000)*0.01;

printf(“bonus=%d”,bonus);

}

3.由键盘输入三个整数a、b、c,用条件运算符求出其中最大值和最小值。

【分析与提示】首先比较输入的a,b 的大小,并把大数装入max, 小数装入min 中,然后再与c 比较,若max 小于c,则把c 赋予max;如果c 小于min,则把c 赋予min。因此max 内总是最大数,而min 内总是最小数。最后输出max 和min 的值即可。

参考代码:

main( )

{

int a,b,c,max,min;

scanf(“%d,%d,%d”, &a,&b,&c);

max=a>b?a:b ;

max=max>c?max:c;

min=a<b?a:b;

min=min<c?min:c;

printf(“最大值为:%d,最小值为:%d\n”,max,min) ;

}

4.有一函数:

x (x<1)

y= 2x-1 (1≤x<10)

3x-11 (x≥10)

编一程序,输入一个x值,输出y值。

【分析与提示】本题考查if语句的嵌套,应当注意if与else的配对关系。从最内层开始,else总是与它上面最近的(未曾配对的)if 配对。

参考代码:

main( )

{

float x,y;

printf(“请输入x的值 \n”) ;

scanf(“%f”, &x);

if(x<1) y=x;

else

if(x>=10) y=3*x-11;

else y=2*x-1;

printf(“x=%6.2f,y=%6.2f”,x,y) ;

}

5.从键盘上输入星期号,并显示该日期的英文名字。

【分析与提示】本实例知识点:switch语句。

switch语句的控制流程是:首先计算表达式的值,然后依次与每一个case中的常量值进行比较,一旦发现了某个能够匹配的值,就执行该case后面的语句组,直到遇到break语句为止。如果表达式的值与所有case中的常量都不匹配,则执行default后面的语句组。

参考代码:

main( )

{

int xqh;

char ywm;

printf(“请输入星期号(1~7):\n”);

scanf(“%d”,&xqh);

switch(xqh)

{ case 1: printf(“Monday”); break;

case 2: printf(“Tuesday”); break;

case 3: printf(“Wednesday”); break;

case 4: printf(“Thursday”); break;

case 5: printf(“Friday”); break;

case 6: printf(“Saturday”); break;

case 7: printf(“Sunday”); break;

default:printf(“error”);

}

}

6.某市不同车牌的出租车3公里的起步价和计费分别为:夏利7元/公里,3公里以外2.1元/公里;富康8元/公里,3公里以外2.4元/公里;桑塔纳9元,3公里以外2.7元/公里。编程:从键盘输入乘车的车型及行车公里数,输出应付车资。

【分析与提示】可设三个变量,分别表示乘车的车型、行车公里数和应付车资,根据乘车的车型和行车公里数,计算出应付的车资。

参考代码:

main( )

{

int cx; /*定义乘车的车型变量cx */

float gl, cf; /*定义行车公里数变量gl、应付车资变量cf */

printf(“\t1-夏利\n \t2-富康\n \t3-桑塔纳\n”);

printf(“\t请输入车型(1-3): “);

scanf(“%d”,&cx);

printf(“\n\t请输入行车公里数: “);

scanf(“%f”,&gl);

switch(cx)

{ case 1: if(gl<=3) cf=7.0;

else cf=7+(gl-3)*2.1 ;break;

case 2: if(gl<=3) cf=8.0;

else cf=8+(gl-3)*2.4 ;break;

case 3: if(gl<=3) cf=9.0;

else cf=9+(gl-3)*2.7 ;

}

printf(“应付车资为%.1f\n”,cf);

}

7.给一个不多于5位的正整数,要求:①求出它是几位数;②分别打印出每一位数字;③按逆序打印出各位数字。如原数为12345,则逆序为54321。

【分析与提示】本题的思路是:设5个变量,分别代表个位、十位、百位、千位和万位。从个位起,依次将各个位取出来,按取出的顺序组合成新的数据,并记录当前取出的数字的个数。

参考代码:

#include “stdio.h”

main( )

{

unsigned x,m,n=0,w=0;

unsigned ge=0,shi=0,bai=0,qian=0,wan=0;

printf(“请输入一个正整数”);

scanf(“%u”,&x);

m=x;

ge=m%10; m=m/10; w=1; n=ge;

if(m)

{shi=m%10; m=m/10; w=2; n=n*10+shi;

if(m)

{bai=m%10; m=m/10; w=3; n=n*10+bai;

if(m)

{qian=m%10; m=m/10; w=4; n=n*10+qian;

if(m)

{wan=m; w=5; n=n*10+wan;}

}

}

}

printf(“\n%u为%u位数”,n,w);

printf(“\n正整数的原序为:%u”,x);

printf(“\n正整数的逆序为:%u”,n);

}

注:当该程序输入一个较大的5位数时,输出结果就不正确了,思考为什么?动手试一下怎样修改该程序。

第5章 循环结构程序设计

一、填空题

1.下面程序的功能是用“辗转相除法”求两个正整数的最大公约数。请填空。

#include

main()

int r,m,n;

scanf(”%d%d”,&m,&n);

if(m<n) (1) ;

r=m%n;

while(r){m=n;n=r; (2) ;}

printf(”%d\n”,n);

【分析与提示】辗转相除法:两数相除,若不能整除,则以除数作为被除数,余数作为除数,继续相除,直到余数为0时,当前除数就是最大公约数。

【解答】(1)r=m;m=n;n=r; (2)r=m%n;

二.运行程序写结果

1.下列程序运行的运行结果为 。

#include

main()

int y=10;

do

{y–;

}while(–y);

printf(”%d”,y–);

【分析与提示】注意 y– 与y–的运算顺序。

【解答】 0

2.下列程序运行的运行结果为 。

main()

{

int x=3,y=6,z=2;

while(x++!=(y-=1))

{

z+=1;

if(y<x)

break;

printf(“%d,%d,%d\n”,x,y,z);

}

}

【解答】4,5,3

3.下列程序运行的运行结果为 。

main()

{

int a=1,b=0;

for( ;a<3 ;a++)

switch(a++)

{

case 1:b–;

case 2:b++;

case 3:b+=3;break;

}

printf(“%d\n”,b);

}

【解答】3

4.下列程序运行的运行结果为 。

main()

{

int x=10,y=10,i;

for(i=0;i<2 ;y=i++)

printf(“%4d%4d”,x–,y);

}

【解答】10 10 9 0

三. 编程题

1.求s=1+2+4+8+…+64的值。

【分析与提示】本题为数学项求和问题,数学项间的关系为:第n项的值为第n-1项的值2倍。参考代码:

main( )

{

int i,s=0,t=1;

while(t<=64)

{ s=s+t;

t=2*t;

}

printf(“s=%d\n”,s);

}

2.求s=1+1/2+1/3+…+1/100的值。

【分析与提示】本题为分数数学项求和问题,要想得到每一项的正确结果,分式中的分子、分母至少要有一个为实型数据。

参考代码:

main( )

{int i;

float s=0,t;

for(i=1;i<=100;i++)

{ t=1.0/i;

s=s+t;

}

printf(“s=%.2f\n”,s);

}

3.求T=1!+2!+3!+…+10!的值。

【分析与提示】本题为数学项求和问题,数学项间的关系为:第n项的值为第n-1项的n倍。参考代码:

main( )

{

long int t=0,tn=1;

int i;

for(i=1;i<=10;i++)

{ tn=i*tn;

t=t+tn;

}

printf(“t=%ld”,t);

}

4.求s=2/1+3/2+4/3+5/4+…+22/21的值。

【分析与提示】请抓住分子与分母的变化规律。

参考代码:

main( )

{

int m;

float s=0,n=2.0;

for(m=1;m<=21;m++)

{ s=s+n/m;

n=n+1;

}

printf(“s=%.2f\n”,s);

}

5.输入一行字母,分别统计其中的英文字母、空格、数字和其他字符的个数。

【分析与提示】利用while语句,条件为输入的字符不为’\n’.

参考代码:

#include “stdio.h”

main( )

{

char c;

int letters=0,space=0,digit=0,other=0;

printf(“请输入一行字符:\n”);

while((c=getchar())!=’\n’)

{ if(c>=’a’&&c=’A’&&c<=’Z’)

letters++;

else if(c==’ ’)

space++;

else if(c>=’0’&&c<=’9’)

digit++;

else other++;

}

printf(“字母数=%d 空格数= %d 数字数=%d 其它字符数=%d\n”,letters,space,digit,other);

}

6.求100以内能被8整除的数,并求它们的和。

【提示】判断一个数m能否被n整除的方法是:将m对n取余数,若余数为0,则为整除。

参考代码:

main( )

{

int n,s=0;

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

if(n%8==0)

{s=s+n;

printf(“%4d”,n);

}

printf(“\ns=%d\n”,s);

}

7.打印出所有的“水仙花数”。所谓“水仙花数”是指一个三位数,其中各位数字的立方和等于该数本身。例如153=13 +53 +33 。

【分析与提示】利用for 循环控制100~999 个数,每个数分解出个位,十位,百位。

参考代码:

main( )

{

int i,j,k,n;

printf(“水仙花数是: “);

for(n=100;n<1000;n++)

{i=n/100;

j=n/10-i*10;

k=n%10;

if(n= =i*i*i+j*j*j+k*k*k)

printf(“%5d”,n);

}

printf(“\n”);

}

8.以下面的格式,输出九九乘法表。

1*1=1

1*2=2 2*2=4

1*3=3 2*3=6 3*3=9

… … …

1*9=9 2*9=18 3*9=27 …9*9=81

【提示】分行与列考虑,共9行9列,利用双重for 循环,外循环i控制行,内循环j控制列。参考代码:

main( )

{int i,j;

for(i=1;i<10;i++)

{ for(j=1;j<=i;j++)

printf(“%d*%d=%-4d”,j,i,j*i);

printf(“\n”);

}

}

9.用for循环打印输出以下图案。

* * * * *

* * * * * * *

* * * * * * * * *

* * * * * * * * * * *

(图形a) ( 图形b)

输出图形a程序代码:

#include “stdio.h”

main( )

{

int i,j,k;

for(i=0;i<4;i++) /*控制打印行数*/

{

for(j=0;j<10+i;j++) /*控制空格输出位置*/

printf(” “);

for(k=0;k<4;k++) /*控制每行*的输出个数*/

printf(“*”);

printf(“\n”);

}

}

输出图形b序代码:

#include “stdio.h”

main( )

{

int i,j,k;

for(i=0;i<4;i++) /*控制打印行数*/

{

for(j=0;j<3-i;j++) /*控制空格输出位置*/

printf(“ ”);

for(k=0;k<2*i+1;k++) /*控制每行*的输出个数*/

printf(“*”);

printf(“\n”);

}

}

10.猴子吃桃子问题。猴子第一天摘下若干个桃子,当即吃了一半,还不过瘾,又多吃了一个。第二天早上又将剩下的桃子吃掉一半,又多吃了一个。以后每天早上都吃了前一天剩下的一半零一个。到第十天早上再想吃时,见只剩一个桃子了。求第一天共摘了多少个桃子。

【提示】采取逆向思维的方法,从后往前推断。参考代码:

main( )

{ int day,x1,x2;

day=9;

x2=1;

while(day>0)

{x1=(x2+1)*2;

x2=x1;

day–;

}

printf(“桃子总数=%d\n”,x1);

}

11.求出500以内所有素数。

【提示】判断素数的方法:用一个数分别去除2到sqrt(这个数),如果能被整除,则表

明此数不是素数,反之是素数。

参考代码:

#include “math.h”

main( )

{int m,k,i,n=0;

for(m=2;m<=500;m++)

{

k=sqrt(m);

for(i=2;i<=k;i++)

if(m%i==0) break;

if(i>=k+1)

{ printf(“%-5d”,m);

n=n+1;

if(n%10==0)

printf(“\n”);

}

}

printf(“\n”);

}

12.输入一个整数(0~99999),判断它的位数,并重新组合成同样位数的最大值。如,输入1345,输出5431。

【提示】先求出该整数的位数;其次分解出每一位数(个位、十位、百位、千位、万位);接着将5个位数进行排序;最后根据整数的位数重新组合成同样位数的最大值。

参考代码:

main( )

{long int num, t,d1,d2,d3,d4,d5,n;/*分别代表个位,十位,百位,千位,万位和位数*/

printf(“请输入一个整数(0~99999):”) ;

scanf(“%ld”, &num);

if(num>9999) n=5;

else if(num>999) n=4;

else if(num>99) n=3;

else if(num>9) n=2;

else n=1;

printf(“n=%ld\n”,n) ;

d5=num/10000;

d4=(num-d5*10000)/1000;

d3=(num-d5*10000-d4*1000)/100;

d2=(num-d5*10000-d4*1000-d3*100)/10;

d1=num-d5*10000-d4*1000-d3*100-d2*10;

if(d5<d4)

{t=d5;d5=d4;d4=t;}

if(d5<d3)

{t=d5;d5=d3;d3=t;}

if(d5<d2)

{t=d5;d5=d2;d2=t;}

if(d5<d1)

{t=d5;d5=d1;d1=t;}

if(d4<d3)

{t=d4;d4=d3;d3=t;}

if(d4<d2)

{t=d4;d4=d2;d2=t;}

if(d4<d1)

{t=d4;d4=d1;d1=t;}

if(d3<d2)

{t=d3;d3=d2;d2=t;}

if(d3<d1)

{t=d3;d3=d1;d1=t;}

if(d2<d1)

{t=d2;d2=d1;d1=t;}

switch(n)

{ case 5: num=d5*10000+d4*1000+d3*100+d2*10+d1; break;

case 4: num=d5*1000+d4*100+d3*10+d2; break;

case 3: num=d5*100+d4*10+d3; break;

case 2: num=d5*10+d4; break;

case 1: num=d5;

}

printf(“重组后的数为:%ld\n”,num);

}

13.求证100以内哥德巴赫猜想是成立的。即:100以内任何一个大的偶数(大于等于6)都可以表示成两个素数之和。

【分析与提示】我们先不考虑怎样判断一个数是否为素数,而从整体上对这个问题进行考虑,可以这样做:读入一个偶数n,将它分成p和q,使n=p+q。怎样分呢?可以令p从2开始,每次加1,而令q=n-p,如果p、q均为素数,则正为所求,否则再试。

参考代码:

#include

#include

main( )

{

int j,n,p,q,flagp,flagq;

printf(“please input n :\n”);

scanf(“%d”,&n );

if (((n%2)!=0)||(n<=4))

printf(“input data error!\n”);

else

{ p = 1 ;

do {

p = p + 1 ;

q = n – p ;

flagp = 1 ;

for(j=2;j<=(int)(sqrt§);j++) /*判断p是否为素数*/

{ if((p%j)==0)

{ flagp = 0 ;

break; /*不是素数,退出循环*/

}

}

flagq=1 ;

for(j=2;j<=(int)(sqrt(q));j++) /*判断q是否为素数*/

{ if ((q%j)==0)

{ flagq = 0 ;

break ; /*不是素数,退出循环*/

}

}

} while(flagp*flagq==0);

printf(“%d=%d+%d\n”,n,p,q) ;

}

}

第6章 数组与指针

一.简答题

1、什么是数组,为什么在C语言中引用数组?

【解答】数组是有序的、且具有相同性质类型的数据集合。引用数组来实现成批地处理数据。

2、在C语言中如何表示一个字符串?

【解答】运用字符型数组来表示字符串。

3、指针是指什么?

【解答】指针就是地址。

二.运行程序写结果

1.以下程序的执行结果是 。

main()

{

int k,a[6]={1,2,3,4,5,6};

for(k=5;k>0;–k)

if(a[k]%2==0)

printf(“%d “,a[k]);

}

【提示】从后向前把能被2整除的数组元素输出。

【解答】6 4 2

2.以下程序的执行结果是 。

#include

main()

{

char str[]=“SSSWLIA”,c;

int k;

for(k=2;(c=str[k])!=’\0’;k++)

{

switch©

{

case ‘I’:++k;break;

case ‘L’:continue;

default:putchar©;continue;

}

putchar(’*’);

}

}

【提示】从字符串中第3个字符开始,把符合要求的字符运用输出字符函数putchar()输出;最后在其后输出一个”*”。

【解答】SW*

3.以下程序的执行结果是 。

main()

{

char ss[10]=“12345”;

strcat(ss,“6789”);

gets(ss);

printf(“%s”,ss);

}

假设输入”ABC”

【分析与提示】运用字符串连接函数strcat(),把两个串”12345″和”6789″连接,对其重新赋值后,原有数值被刷新输出新值。

【解答】“ABC”

4.以下程序的执行结果是 。

# include

main()

{

char a[]=“Monday”,b[]=“day”;

strcpy(a,b);

printf(“%s\t%s\n”,a,b);

printf(“%c\t%c\n”,a[4],a[5]);

}

【分析与提示】把b字符串的内容拷贝到a字符串中,分别显示a和b串内容;再显示数组元素a[4]和a[5]的内容。

【解答】day day

a y

5.以下程序的执行结果是 。

main()

{

int x[8]={8,7,6,5,0,0},*s;

s=x+3;

printf(“%d”,s[2]);

}

【分析与提示】运用指针显示数组元素值。需要注意的是把数组x第3个元素的地址,赋给了指针变量s,所以s[2]里面存储的是x[5],即0。

【解答】0

6.以下程序的执行结果是 。

main()

{

int a=7,b=8,*p,*q,*r;

p=&a;q=&b;

r=p;p=q;q=r;

printf(“%d,%d,%d,%d”,*p,*q,a,b);

}

【分析与提示】指针变量存储地址,而不是数值。

【解答】8,7,7,8

7.以下程序的执行结果是 。

main()

{

char a[]=“language”,b[]=“programe”;

char *p,*q;

p=a;q=b;

while(*p&&*q)

{

if((*p)==(*q)) printf(“%c”,*p);

p++;q++;

}

}

【分析与提示】程序功能是,输出两个字符串中相同的字符。

【解答】gae

8.以下程序的执行结果是 。

# include

# include

main()

{

char a[80]=“AB”,b[80]=“LMNP”;

int i=0;

strcat(a,b);

while(a[i++]!=’\0’)

b[i]=a[i];

puts(b);

}

【分析与提示】把b串内容连接到a串上,再通过循环对b串重新赋值。

【解答】LBLMNP

三.编程题

1.已有10个数,求它们当中的最大值。

【分析与提示】运用一维数组保存10个数,依次比较保存最大值。

参考代码:

main()

{

int i,a;

int n[10]={8,2,4,6,7,1,0,85,32,54};

a=n[0];

for(i=1;i<10;i++)

if(n[i]>a) a=n[i];

printf(“a=%d\n”,a);

}

2.从键盘输入10个学生的成绩,建立一个一维数组,求学生的平均分。

【分析与提示】把10个学生的成绩保存在一维数组,运用一重循环计算所有成绩的总和,在此基础上计算平均值。

参考代码:

main()

{

int i;

float a[10],sum=0,ave;

printf(“输入10个学生的成绩:”);

for(i=0;i<10;i++)

{

scanf(“%f”,&a[i]);

sum=sum+a[i];

}

ave=sum/10;

printf(“10个学生的平均成绩是%5.2f。”,ave);

}

3.将两个一维整型数组中的对应元素相加后显示出来。

【分析与提示】把数组下标相同的元素值相加。

参考代码:

#include

main()

{

int i;

int x[5]={10,8,7,6,5};

int y[5]={-3,9,-10,-2,4};

int z[5];

for(i=0;i<5;i++)

z[i]=x[i]+y[i];

printf(“\n相加后一维数组为:”);

for(i=0;i<5;i++)

printf(“%d “,z[i]);

}

4.线性查找。

【分析与提示】从数组的第一个元素开始,依次将要查找的数和数组中元素比较,直到找到该数或找遍整个数组为止。

参考代码:

main()

{

int table[10]={2,4,6,8,10,12,14,16,18,20};

int find=0,i,x;

printf(“请输入要找的数: “);

scanf(“%d”,&x);

for(i=0;i<10;i++)

if(x==table[i])

{find=1;break;}

if(find==1)

printf(“%d在table[%d]中\n”,x,i);

else

printf(“没有找到数%d\n”,x);

}

5.求一个4×4矩阵对角线元素之和。

【分析与提示】若设置矩阵行列坐标分别为i和j,则对角线元素下标满足以下条件:i==j或i+j=3。

参考代码:

main()

{

int a[4][4] ,i,j,sum=0;

for(i=0;i<4;i++)

for(j=0;j<4;j++)

{

scanf(“%d”,&a[i][j]);

if(ij||i+j3) sum=sum+a[i][j];

}

printf(“对角线元素之和:%d”,sum);

}

6.将两个二维数组对应元素加起来,存到另一个二维数组中。

【分析与提示】运用双重循环,把行列下标均相同的元素值相加。

参考代码:

main()

{

int a[3][2]={10,20,30,40,50,60};

int b[3][2]={1,4,2,5,3,6};

int c[3][2];

int i,j;

for(i=0;i<3;i++)

{

for(j=0;j<2;j++)

{

c[i][j]=a[i][j]+b[i][j];

printf(“%4d”,c[i][j]);

}

printf(“\n”);

}

}

7.找出一个二维数组中的鞍点。

【分析与提示】所谓鞍点指该位置上的数在该行上最大,在该列上最小。注意并不是所有的二维数组都有鞍点。

参考代码:

#define N 3

#define M 3

main()

{

int a[M][N],(*p)[N]; /* p 为指向一维数组的指针*/

int max,maxi,maxj;

int i,j,k,m,n;

int flag1=0,flag2=0;

p=a;

printf(“给数组输入数据:\n”);

for(i=0;i<M;i++)

for(j=0;j<N;j++)

scanf(“%d”,p[i]+j);

for(i=0;i<N;i++)

{

max=*p[i];

for(j=0;j<M;j++)

if(*(p[i]+j)>max)

{max=*(p[i]+j);maxj=j;}

for(k=0,flag1=1;k<N&&flag1;k++)

if(max>*(p[k]+j) ) flag1=0;

if(flag1)

{

printf(“\n第%d行,第%d列的%d是鞍点!\n”,i,maxj,max);

flag2=1;

}

}

if(!flag2)

printf(“\n矩阵中无鞍点!”);

}

8.用指针数组给一个整型二维数组输入数值,并求出各行元素的和。

【分析与提示】用二维数组a各行的首地址赋予指针数组p的各个元素,通过此循环嵌套,为各个数组元素赋值。

main( )

{

int a[3][3],*p[3],i,j,sum;

for(i=0;i<3;i++)

p[i]=a[i]; /*把二维数组a各行的首地址赋予指针数组p的各个元素*/

for(i=0;i<3;i++) /*通过此循环嵌套,为各个数组元素赋值*/

for(j=0;j<3;j++)

scanf(“%d”,p[i]+j);

printf(“和分别为:”);

for(i=0;i<3;i++) /*通过此循环嵌套,求各行数组元素的和*/

{

sum=0;

for(j=0;j<3;j++)

sum=sum+*(p[i]+j);

printf(” %d “,sum); /*分行输出每一行的和值*/

}

}

9.用指针实现合并两个字符串。

【分析与提示】把第二个字符串中字符逐个赋值给第一个字符串,需要注意的是两个字符数组下标变量的初值不同。

参考代码:

#include

#include

main()

{

char s1[40],s2[20],*p1,*p2;

int i,j,n;

p1=s1;p2=s2;

printf(“输入第一个字串:”);

gets(p1);

printf(“\n输入第二个字串:”);

gets(p2);

n=strlen(p1);

for(i=n,j=0;*(p2+j)!=’\0’;i++,j++)

*(p1+i)=*(p2+j);

*(p1+i)=’\0’;

printf(“\n输出合并后字串为:”);

puts(p1);

}

10.从输入的5个字符串中找出最长的一个字符串输出。

【分析与提示】运用测试字符串长度函数strlen,进行串比较。

参考代码:

# include

# include

main()

{

char a[5][80],*sp;

int i;

for(i=0;i<5;i++)

gets(a[i]);

for(i=0;i<5;i++)

if(strlen(sp)<strlen(a[i])) sp=a[i];

printf(“the longest string is %s”,sp);

}

第7章 函数与指针

一**.运行程序写结果**

1.下列程序运行的结果为 。

int x1=30,x2=40;

main()

{

int x3=10, x4=20;

swap(x3,x4);

swap(x2,x1);

printf(“%d,%d,%d,%d\n”,x3,x4,x1,x2);

}

swap(int x,int y)

{x1=x;x=y;y=x1;}

【提示】本题考查全局变量的作用范围。

【解答】 10,20,40,40

2.下列程序运行的结果为 。

#include

void num()

{

extern int x,y;

int a=15,b=10;

x=a-b;y=a+b;

}

int x,y;

main()

{

int a=7,b=5;

x=a+b;y=a-b;

num();

printf(“%d,%d\n”,x,y);

}

【分析与提示】用extern进行外部变量说明。

【解答】5,25

3.下列程序运行的结果为 。

main()

{int a[5]={5,10,-7,3,7},i,j,t;

sort(a);

for(i=0; i<=4; i++)

printf(“%3d”,a[i]);

}

sort(int a[])

{int i,j,t;

for(i=0; i<4; i++)

for(j=0; j<4-i; j++)

if(a[j]>a[j+1])

{t=a[j]; a[j]=a[j+1]; a[j+1]=t;}

}

【提示】该程序的功能是将5个数由小到大进行排序。

【解答】 -7 3 5 7 10

4.下列程序运行的结果为 。

#define SQR(x) 2*x+1

main()

{int a,b,c;

a=3;b=2;c=1;

a*=SQR(b+c)/ SQR(b+c);

printf(“%d\n”,a);

}

【提示】a*=SQR(b+c)/ SQR(b+c);宏展开为a*=2*b+c+1/2*b+c+1;

【解答】21

5.下列程序运行的结果为 。

void swap1(int x,int y)

{int t;

t=x;x=y;y=t;

return;

}

void swap2(int *x,int *y)

{int t;

t=*x;*x=*y;*y=t;

return;

}

main()

{int x=3,y=5;

printf(“%d,%d\n”,x,y);

swap1(x,y);

printf(“%d,%d\n”,x,y);

swap2(&x,&y) ;

printf(“%d,%d\n”,x,y);

}

【提示】注意指针变量做函数参数时,改变形参的值就等同与改变了实参的值。

【解答】3,5

3,5

5,3

6.下列程序运行的结果为 。

long fib(int g)

switch(g)

Case 0: return 0;

case 1:

case 2: return 1;

return(fib(g-1)+fib(g-2));

main()

{

long k;

k=fib(7);

printf(“k=%ld\n”,k);

【提示】注意函数递归调用的条件。

【解答】k=13

二.编程题

1.已知圆的半径为R,求它的面积。

#include /* 包含文件 */

#include /* 包含数学库函数 */

#define PI 3.14159 /* 宏定义 */

main( ) /* 主函数 */

{

float area(float); /* 函数area的原型 ,即函数说明 */

float r,s; /* 主函数中的局部变量定义 */

printf(“ 请输入半径: \n”);

scanf(“%f”,&r);

s=area®; /* 调用area函数 */

printf(“圆的半径为:%f\n”,r);

printf(“圆的面积为:%f\n”,s);

}

float area(float a) /* 定义函数area */

{ float d;

d=PI*a*a;

return(d); /* 返回计算结果 */

}

【提示】本程序由主函数main()和自定义函数area()组成。程序的前2句是文件包含语句,即把输入、输出标准函数和数学函数的文件包含到本程序中。第3句是宏定义语句,即用标识符PI来代替数字3.14159。

运行:请输入半径: 1.1 ↙

显示:圆的半径为:1.1

圆的面积为:3.801324

2.编写一个函数输出三个数中的最大值。

【提示】在main()函数中输入数据,调用求3个数最大值函数。

int max(int x,int y,int z)

{

int t ;

if(x>=y) t=x ;

else t=y;

if(t<z) t=z;

return(t);

}

main()

{

int x,y,z;

printf(“input 3 numbers:”);

scanf(“%d%d%d”,&x,&y,&z);

printf(“max=%d\n”,max(x,y,z));

}

3.编写一个函数,将一个任意三位数n逆序输出。即若n=456,则输出654。

【提示】将一个三位数n分解为个位、十位和百位分别放入c,b,a中,然后逆序输出。

int rec(int x)

{

int a,b,c ;

a=x/100;

b=x%100/10;

c=x%10;

return(c*100+b*10+a);

}

main()

{

int rec(int x);

int y,z;

printf(“input a number(100-999):”);

scanf(“%d”,&y);

z=rec(y);

printf(“the changed number is :%d\n”,z);

}

4.编写比较两字符串是否相等的函数。

【提示】 按ASCII码值大小比较,将两个字符串自左至右逐个字符相比,直到出现不同的字符或遇到’\0’为止。如果全部字符相同,则认为相等,如果出现不同的字符,则以第一个不同的字符的比较结果为准。比较结果由函数值带回。

参考代码:

#include

int cmp( );

main( )

{

int resu;

char s1[100],s2[100];

printf(“Please input s1:\n”);

gets(s1) ;

printf(“Please int s2:\n”);

gets(s2);

resu=cmp(s1,s2);

printf(“%s与%s的比较结果是%d.”,s1,s2,resu);

}

int cmp(s1,s2)

char s1[ ],s2[ ];

{int i=0;

while((s1[i]==s2[i])&&(s1[i]!=0)&&(s2[i]!=0))

i++;

if(s1[i]’\0’&&s2[i]’\0’)

return 0;

else

return(s1[i]-s2[i]);

}

5.编写求字符串长的函数。

【提示】字符串的长度不包括’\0’在内。

参考代码:

#include

main()

{int test();

int n;

char str[100];

gets(str);

n=test(str);

printf(“the numbers is :%d\n”,n);

}

int test(str)

char str[];

{int n=0;

while(str[n]!=’\0’)

n++;

return(n);

}

6.编写一个函数判定一个数是否是素数,在主函数中调用该函数,输入一个整数,输出是否是素数的信息。

【分析与提示】由主函数任意输入一个整数m,将其值传递给子函数isprime(m)由子函数判断这个数是否为素数,是return(1),否则return(0)。

参考代码:

#include

main()

{ int m;

printf(“Please input a data m=:”);

scanf(“%d”,&m);

isprime (m);

}

isprime(int n)

{

int i,k;

k=n/2;

for(i=2;i<=k;i++)

if (n%i==0) break;

if(i>=k+1)

printf(“This is a prime number”);

else printf(“This is not a prime number”);

}

7.用指针写一个删除字符串中空格的函数。

【提示】用指针p1指向待处理的字符串,用*p1从串头到串尾逐一走动,每走到一个字符判断其是否为空格,若不是空格,则将其保存到指针*p2中。

参考代码:

#include

void dele(char *str)

{

char *p1,*p2;

for(p1=p2=str;*p1!=’\0’;p1++)

if(*p1==’ ’) continue;

else *p2++=*p1;

*p2=’\0’;

}

main( )

{

char str[100];

gets(str);

dele(str);

puts(str);

}

8.用指针写合并两个字符串的函数。

【分析与提示】先将字符串str1从串头到串尾逐一拷贝到字符串str3中,接着将字符串str2从串头到串尾逐一拷贝到字符串str3中。

参考代码:

#include

char unitestring(char *str1,char *str2,char *str3) /*合并函数*/

{

int i=0;

while((*str1)!=’\0’)

{ *(str3+i)=*str1;

i++;

str1++;

}

while((*str2)!=’\0’)

{*(str3+i)=*str2;

i++;

str2++;

}

*(str3+i)=’\0’; /*不能自动加入\0*/

}

main( )

{

char p[50],q[50],r[100]; /*r为连接后的字符串*/

printf(“Please enter the first string:\n”);

gets§; /*输入字符串*/

printf(“Please enter the second string:\n”);

gets(q); /*输入字符串*/

unitestring(p,q,r);

puts®; /*输出结果*/

}

9.输入15个正整数,放在a数组中,要求:奇数放在a数组前部,偶数放在a数组后部。再分别对奇数和偶数排序。

【分析与提示】在main函数中将数组中的奇数放在a数组前部,偶数放在a数组后部。在分别两次调用sort函数将奇数和偶数进行排序。

参考代码:

void sort();

main()

{

int a[15];

int i,j=14,n=0,t;

for(i=0;i<15;i++)

scanf(“%d”,&a[i]);

i=0;

while(j>=i)

{

if(a[i]%2!=0)

{i++;n++;}

else

{t=a[i];a[i]=a[j];a[j]=t;j–;}

}

sort(a,n);

sort(&a[n],15-n);

for(i=0;i<15;i++)

printf(“%3d”,a[i]);

printf(“\n”);

}

void sort(a,n)

int a[];

int n;

{

int i,j,t;

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

for(i=0;i<n-j;i++)

if(a[i]>a[i+1])

{t=a[i];a[i]=a[i+1];a[i+1]=t;}

}

10.编写一个程序完成“菜单”功能。提供三种选择途径:

(1)求水仙花数(narcissus number),找出100至999之间的所有水仙花数。

(2)求出素数(prime number),找出2至n之间的所有素数。

(3)求Faibonacci数列前n项的值。

#include “math.h”

main()

{ int m, xz;

void narcissus( );

void prime( );

void faibonacci( );

clrscr( );

m=0;

while(m==0)

{ printf(“\n\n”);

printf(“ 1 find narcissus number\n”);

printf(“ 2 find prime number\n”);

printf(“ 3 find Faibonacci number\n”);

printf(“ other number exit!\n”);

printf(“ input number please!\n”);

scanf(“%d”,&xz);

switch(xz)

{ case 1: narcissus( ); break;

case 2: prime( ); break;

case 3: faibonacci( ); break;

default: m=1;

}m=1;

}

}

void narcissus( )

{ int k,a,b,c,d;

for (k=100; k<1000; k++)

{ a=k/100;

b=k%100/10;

c=k%10;

d=a*a*a+b*b*b+c*c*c;

if (d==k) printf(“%5d\n”, k);

}

}

void prime ( )

{ int i, j, k, n, m=0;

printf(“input n please !\n”);

scanf(“%d”, &n);

for(i=2; i<n; i++)

{ j=sqrt(i);

for(k=2; k<=j; k++) if (i%k==0) break;

if (k>j)

{ m++;

printf(“%6d”, i);

if (m%10==0) printf(“\n”);

}

}

}

void faibonacci( )

{ long f1, f2;

int k, n;

printf(“int n please!\n”);

scanf(“%d”, &n);

f1=1; f2=1;

for (k=1; k<=n/2; k++)

{ printf(“%8d%8d”, f1, f2);

if (k%20) printf(“\n”);

f1=f1+f2;

f2=f1+f2;

}

}

【提示】程序共有4个函数,其中主函数提供了主菜单,允许选择三种情况之一,否则就退出。通过开关语句switch进行选择。为了不断的提供菜单,用while来永远循环。一开始给变量m赋值为0,m=0就继续循环,一旦选择了不存在的情况,则将m置1,循环就结束。

7.2 补充习题

一.单选题

1.以下程序的输出结果是( )

fun(int x,int y,int z)

{ z=x*x+y*y;}

main( )

{ int a=31;

fun(5,2,a);

printf(“%d”,a);

}

A、 0 B、 29 C、 31 D、 无定值

【分析与提示】变量作参数时,形参值的改变不会影响实参的值。

【解答】答案:C

2.当调用函数时,实参是一个数组名,则向函数传送的是( )

A、数组的长度 B、数组的首地址

C、数组每一个元素的地址 D、数组每个元素中的值

【解答】答案:B

3.以下程序的输出结果是( )

int f( )

{static int i=0;

int s=1;

s+=i;i++;

return s;

}

main( )

{int i,a=0;

for(i=0;i<5;i++) a+=f();

printf(“%d\n”,a);

}

A、20 B、24 C、25 D、15

【分析与提示】自动变量在函数每次调用时,都进行初始化,而静态变量只在编译阶段初始化一次。

【解答】答案:D

4.以下程序运行后的输出结果是( )

f(int b[ ],int m,int n)

{int i,s=0;

for(i=m;i<n;i=i+2) s=s+b[i];

return s;

}

main( )

{int x,a[ ]={1,2,3,4,5,6,7,8,9};

x=f(a,3,7);

printf(“%d\n”,x);

}

A、10 B、18 C、8 D、15

【分析与提示】数组名作参数时传送的是数组的首地址。

【解答】答案:A

5.当执行下面的程序时,如果输入ABC,则输出结果是( )

#include “stdio.h”

#include “string.h”

main( )

{ char ss[10]=“1,2,3,4,5”;

gets(ss);strcat(ss,“6789”);printf(“%s\n”,ss);

}

A、ABC6789 B、ABC67 C、12345ABC6 D、ABC456789

【分析与提示】注意库函数gets()、strcat()的用法。

【解答】答案:A

6.以下程序运行后的输出结果是( )

void fun(char *c,int d)

{*c=*c+1;d=d+1;

printf(“%c,%c,”,*c,d);

}

main()

{char a=‘A’,b=‘a’;

fun(&b,a);

printf(“%c,%c\n”,a,b);

}

A、 B,a,B,a B、 a ,B,a,B C、 A,b,A,b D、b,B,A,b

【分析与提示】注意指针作参数与普通变量作参数的“值传递”。

【解答】答案:D

7.以下程序运行后的输出结果是( )

void sort(int a[],int n)

{ int i,j,t;

for(i=0;i<n-1;i++)

for(j=i+1;j<n;j++)

if(a[i]

{t=a[i];a[i]=a[j];a[j]=t;}

}

main()

{int aa[10]={1,2,3,4,5,6,7,8,9,10},i;

sort(&aa[3],5);

for(i=0;i<10;i++)

printf(“%d,”,aa[i]);

printf(“\n”);

}

A、 1,2,3,4,5,6,7,8,9,10,

B、10,9,8,7,6,5,4,3,2,1,

C、 1,2,3,8,7,6,5,4,9,10,

D、1,2,10,9,8,7,6,5,4,3,

【分析与提示】注意实参的“值”。

【解答】答案:C

8.以下程序运行后的输出结果是( )

int f(int n)

{if(n==1) return 1;

else return f(n-1)+1;

}

main()

{int i,j=0;

for(i=1;i<3;i++)

j+=f(i);

printf(“%d\n”,j);

}

A、 4 B、 3 C、 2 D、 1

【分析与提示】本题为递归调用。

【解答】答案:B

二.运行程序写结果

1.下列程序运行的运行结果为 。

#include “stdio.h”

main()

{

int i,num;

for(i=0;i<3;i++)

{num=2;

printf(“\n The num equal:%d \n”,num);

num++;

{

static int num=1;

printf(“\nThe internal block num equal: %d\n”,num);

num++;

}

}

}

【分析与提示】注意static的用法。

【解答】The num equal:2

The internal block num equal:1

The num equal:2

The internal block num equal:2

The num equal:2

The internal block num equal:3

2.下列程序运行的运行结果为 。

#include “stdio.h”

int a,b,c;

void add()

{extern int a;

c=a+b;

}

void main()

{ a=b=4;

add();

printf(“The value of c is equal to %d\n”,c);

}

【分析与提示】注意xternal的用法。

【解答】The value of c is equal to 8

3.下列程序运行的运行结果为 。

void swap(int *a,int *b)

{int *t;

t=a;a=b;b=t;

}

main()

{int x=3,y=5,*p=&x,*q=&y;

swap(p,q);

printf(“%3d%3d\n”,*p,*q);

}

【分析与提示】指针作参数时,形参指针的改变不会影响实参。

【解答】 3 5

三.改错题

1.下列给定程序中,函数fun的功能是计算正整数num的各位上的数字之平方和。

例如,输入352,则输出应该是38;若输入328,则输出应该是77。

请改正程序中的错误,使它能得出正确的结果。

注意,不要改动main函数,不得增行或删行,也不得更改程序的结构。两处错误分别在/**********found************/的下一行。

程序代码:

#include

#include

long fun(long num)

{

/**********found************/

long k=1;

do

{

k+=(num%10)*(num%10) ;

num/=10;

/***********found***********/

}while(num)

return(k) ;

}

main()

{

long n;

clrscr( );

printf(“\n Please enter a number:”);

scanf (“%ld”,&n);

printf(“\n %ld\n”,fun(n));

}

【分析】错误1:k用来存放各位数字的平方和,初值应为0。错误2:语法错误。

【解答】(1) long k=0; (2) while(num);

2.下列给定程序中,函数fun的功能是:在字符串str中找出ASCII码值最大的字符,将其放在第一个位置上;并将该字符前的原字符向后顺序移动。

例如,调用fun函数之前给字符串输入:ABCDeFGH,调用后字符串中的内容为:eABCDFGH

请改正程序中的错误,使它能得出正确的结果。

注意,不要改动main函数,不得增行或删行,也不得更改程序的结构。两处错误分别在/**********found************/的下一行。

参考代码:

#include

void fun(char *p)

{

char max,*q;

int i=0;

max=p[i];

while(p[i]!=0)

{

if(max<p[i])

{

max=p[i];

/**********found************/

p=q+i;

}

i++;

}

/***********found***********/

while(q<p)

{

*q=*(q-1);

q–;

}

p[0]=max;

}

void main()

{

char str[80];

printf(“enter a string:”);

gets(str);

printf(“\nthe original string:”);

puts(str);

fun(str);

printf(“\nthe string after moving:”);

puts(str);

}

【分析与提示】本例考查指针指向字符串的操作。第一个错误出在p=q+i;这一行,经过观察发现,q是没有赋初值的指针,这样的指针指向不明确,是野指针,所以必须给q赋初值,这一语句更改为q=p+i;就对了,作用是把q定位在字符e所在的位置。因此在程序中,q的作用总是指向当前最大的字符。第二个错误比较隐蔽,单从语法上检查不出来,但是分析程序的作用后可发现p是数组的首地址,所以它总是小于或等于q的,而第二个while循环的作用是把e前面的字符顺次往后挪动,所以,这里的循环条件应该是q>p。

【解答】(1)q=p+i; (2)while(q>p)

四.编程题

1.已知e=1+1/1!+1/2!+1/3!+…+1/n!,试用公式求e的近似值,要求累加所有不小于10-6的项值。用函数fun完成任何数的阶乘。

【分析与提示】用主函数完成1与1/1!到1/n!的相加,直到1/n!的值小于10-6,通过形参传递给子函数fun,用1×2×3×…×n求n的阶乘。

参考代码:

#include

int fun();

main()

{

int i;

float e ,n;

e=1.0;

i=1;

n=1.0;

while (n>1.0e-6)

{n=1.0/fun(i);

i++;

e=e+n ;

}

printf (“%f\n” ,e);

}

int fun( int i)

{ int j,k;

k=1;

for (j=1;j<=i ;j++)

k=k*j;

return(k);

}

输出结果:2.718215

2.请编写函数fun(),该函数的功能是:将两个两位的正整数a,b合并形成一个整数放在c中。合并的方式是:将a数的十位和个位数依次放在c数的十位和千位上,b数的十位和个位数依次放在c数的百位和个位上。

例如,当a=45,b=12时,调用到该函数后,c=5142。

注意:部分源程序给出如下。请勿改动主函数main和其他函数中的任何内容,仅在函数fun的花括号中添入所编写的若干语句。

部分源程序:

#include

#include

void fun(int a,int b,long *c)

{

*c=a%10*1000+b/10*100+a/10*10+b%10;

}

main()

{int a,b;

long c;

clrscr();

printf(“Input a,b:”);

scanf(“%d%d”,&a,&b);

fun(a,b,&c);

printf(“The result is :%ld\n”,c);

}

3.请编写函数fun(),该函数的功能是:将s所指字符串中ASCII码值为偶数的字符删除,串中剩余字符形成一个新串放在t所指的数组中

例如,若s所指字符串中的内容为ABCDEFG12345,最后t所指的数组中的内容应是ACEG135。

注意:部分源程序给出如下。请勿改动主函数main和其他函数中的任何内容,仅在函数fun的花括号中添入所编写的若干语句。

部分源程序:

#include

#include

#include

void fun(char *s,char t[])

{

………

}

main()

{

char s[100],t[100];

clrscr();

printf(“\n lease enter string s:”);

scanf(“%s”,s);

fun(s,t);

printf(“\nThe result is :%s\n”,t);

}

参考代码:

int i=0;

for(;*s!=’\0’;s++)

if(*s%2==1)

t[i++]=*s;

t[i]=’\0’;

4. Hanoi 汉诺塔问题。

【分析】这是一个典型的用递归方法解决的问题。问题是这样的:有三根针A、B、C,A针上有64个盘子,盘子大小不等,大的在下,小的在上。要求把这64个盘子从A针移到C针,在移动的过程中可以借助B针,每次只允许移动一个盘子,而且在移动过程中三根针上都保持大盘在下,小盘在上。编写程序并打印出移动的步骤。

将n个盘子从A 针移到C针可以分解为以下三个步骤:

①将A 上n-1个盘子借助C针先移到B针上。

②把A针上剩余的一个盘子移到C针上。

③将n-1 个盘子从B针借助A针移到C盘上。

例如:要想将A针上的3个盘子移到C针上,可以分解为以下三步:

①将A针上的2个盘子移到B针上(借助C针)。

②将A针上的一个盘子移到C针上。

③将B针上的2个盘子移到C针上(借助A针)。

其中第②步可直接实现。

第①步又可以用递归方法分解为:

a、将A上一个盘子从A移到C。

b、将A上一个盘子从A移到B。

c、将C上一个盘子从C移到B。

第③步可以分解为:
a、将B上一个盘子从B移到A上。

b、将B上一个盘子从B移到C上。

c、将A上一个盘子从A移到C上。

将以上综合起来,可以得到移动的步骤为:

A C, A B,C B,A C,B A, B C,A C

上面第①步和第③步,都是把n-1个盘子从一个针移到另一个针上,采用的方法是一样的,只是针的名字不同而已。为使之一般化,可以将①步和③步表示为:

将“one:”针上的n-1个盘子移到“two”针上,借助“three”针。

只是在①步和第③步中,one、two、three和A、B、C的对应关系不同。对于第①步,对应关系是:one —A,two—B,three—C。对于第③步,对应关系是:one—-B、two—C、three—A。因此,可以将上面三个步骤分成两类操作:

第一类:将n-1个盘子从一个针移到另一个针上(n>1)。这是一个递归过程。

第二类:将1个盘子从一个针上移到另一个针上。

下面编写程序,分别用两个函数实现以上两类操作,用hanoi函数实现第一类操作,用move函数实现上述第二类操作。hanoi(n,one,two,three)表示将n个盘子从“one”针移动到“three”针,借助“twe”针,move(getone,putone)表示一个盘子从“getone”针移动到“putone”针。getone和putone也是代表A、B、C针之一,根据每次不同情况分别去A、B、C代入。

程序如下:

void move(char getone, char putone)

{

printf(“%c—> %c\n”, getone, putone);

}

void hanoi(int n, char one, char two, char three )

/*将n个盘子从one借助two,移到three*/

{

if ( n==1) move(one,three);

else { hanoi(n-1, one, three,two);

move(one, three);

hanoi( n-1, two, one, three);

}

}

main( )

{ int m;

printf(“input the number of the diskes :”);

scanf(“%d”,&m);

printf(“the step to move %3d diskes :\n”, m);

hanoi(m, ‘A’, ‘B’, ‘C’);

}

程序运行结果如下:

Input the number of diskes: 3

The step to move 3 diskes:

A—-C

A—-B

C—-B

A—-C

B—-A

B—-C

A—-C

第8章 结构体与共用体

一.简答题

1.结构体类型与以前的标准数据类型有什么区别?

【解答】

(1)结构体类型是一种构造出来的数据类型。它具体代表多少成员还需要由用户定义。基本类型不需要用户定义而可以直接使用,而结构体类型必须先定义类型再使用。

(2)结构体类型是复合数据类型,可简单,也可复杂,而简单数据类型则比较单纯。

(3)用简单类型定义的变量一般都可直接参与多种运算,而结构体变量则往往只能对其成员进行多种运算,对整个结构体变量适用的运算很少。

2.结构体类型与共用体类型有什么异同?

【解答】

(1)结构体和共同体都是构造数据类型,使用它们都可存储多种类型的数据,可以方便地组织不同类型的数据。

(2)结构体占用的空间是所有成员所占用空间的和,而共用体则是最大成员所占据的空间。结构体重在组织多种类型的数据,从而构造一个复杂的数据类型,而共用体重在强调内存的共享与重复使用。

3.枚举类型适用于什么场合?

【解答】枚举类型用于程序中某个项目的所有可能选项是固定的,单一的表达场合时。

4.动态存储分配有什么作用?

【解答】使用动态存储分配内存空间,可以让程序适应用户对内存变化的需要,及事先不能确定内存用量的场合。它以小的牺牲(定义的指针也占用空间)换来了内存使用效率的提高。

5.类型定义有什么意义?

【解答】所谓类型定义,并不是定义了一种新类型,而是为了书写方便或使程序易于阅读,由程序员规定的一种已有类型的新名称而已。

二.运行程序写结果

1.以下程序的执行结果是 。

#include

struct studinf{

char*name;

float grad;

}*p;

main()

{

struct studinf a; p=&a;

p->grad=95.5;

p->name=(char*)malloc(20);

strcpy(p->name, “wang pi”);

printf(“%s\t%2f\n”, p->name, p->grad);

}

【分析与提示】本题旨在检查读者通过指针访问结构体变量的能力。同时,练习指向运算符的用法、动态分配的使用,及结构体中指针成员的使用方法。

【解答】wang pi 95.500000

2.以下程序的执行结果是 。

#include

typedef struct month

{ char month[12];

int days;

} DATE;

DATE monthtab[]={“January”, 31, “February”, 28, “March”, 31, “April”, 30, “May”, 31, “June”, 30, “July”,31, “August”,31, “September”,30, “October”,31, “November”,30, “December”, 31};

main()

{

int i;

for(i=0;i<12;i++)

printf(“%-10s%2d\n”, monthtab[i].month, monthtab[i].days);

}

【分析与提示】本题意在练习比较复杂的类型定义的用法,所以,重点放在定义形式上。

【解答】运行结果如下:

January 31

February 28

March 31

April 30

May 31

June 30

July 31

August 31

September 30

October 31

November 30

December 31

3.以下程序的执行结果是 。

#include

struct test

{char x,y;

};

union exec

{int a;

char b,c;

struct test d;

long e;};

main()

{

union exec var;

printf(“\nSize of union exec = %d bytes.”,sizeof(union exec));

printf(“\nSize of variable var = %d bytes.”,sizeof(var));

var.a=2345;

printf(“\nAddress of var.a is %p, %#x.”,&var.a,var.a);

printf(“\nAddress of var.b is %p, %#x.”,&var.b,var.b);

printf(“\nAddress of var.c is %p, %#x.”,&var.c,var.c);

printf(“\nAddress of var.d is %p, %#x.”,&var.d,var.d);

printf(“\nAddress of var.d.x is %p, %#x.”,&var.d.x,var.d.x);

printf(“\nAddress of var.d.y is %p, %#x.”,&var.d.y,var.d.y);

printf(“\nAddress of var.e is %p, %#x.”,&var.e,var.e);

}

【分析与提示】本题设计的目的是考查读者对结构体和共用体混合使用的认识与理解。通过运行程序,查看结果,并比较源程序进行分析,可加强读者对结构体和共用体的认识。提醒读者注意:2345存储在计算机内是2进制数,表示成16进制是0x929。存储时先存储的是低字节0x29,然后是高字节0x9。

【解答】某次运行的结果如下:

Size of union exec = 4 bytes.

Size of variable var = 4 bytes.

Address of var.a is FFD6, 0x929.

Address of var.b is FFD6, 0x29.

Address of var.c is FFD6, 0x29.

Address of var.d is FFD6, 0x929.

Address of var.d.x is FFD6, 0x29.

Address of var.d.y is FFD7, 0x9.

Address of var.e is FFD6, 0x929.

4.以下程序的执行结果是 。

#include

enum prov{Beijing, Tianjin, Shanghai, Chongqing, Liaoning=5, Heilongjiang, Jilin, Shandong=10, Hebei, Henan}addr;

main()

{

enum prov addr;

printf(“\nBeijing=%d,Tianjin=%d,Shanghai=%d,”,Beijing,Tianjin,Shanghai);

printf(“Chongqing=%d,Liaoning=%d,Heilongjiang=%d,”,Chongqing,Liaoning,Heilongjiang);

printf(“Jilin=%d,Shandong=%d,Hebei=%d,Henan=%d.\n”,Jilin,Shandong,Hebei,Henan);

addr=Shanghai;

addr++;

printf(“\nAddress is %d.\n”,addr);

}

【提示】本题意在熟练读者对枚举类型的认识与使用:如何定义一个枚举类型;如何定义枚举变量;如何在程序中赋值、运算等。特别要指出的是,最后一行的输出只是一个代表本枚举变量的一个整数,而不少初学者往往误认为的是一个字符串(Chongqing)。

【解答】

Beijing=0, Tianjin=1, Shanghai=2, Chongqing=3, Liaoning=5, Heilongjiang=6, Jilin=7, Shandong=10, Hebei=11, Henan=12

Address is 3.

三. 编程题

1.编写一程序,定义一个点的坐标。然后定义两个点,求这两个点间的距离。

【提示】本题属于结构体的简单应用。主要练习如何使用结构体变量的成员参与运算等问题。

参考代码:

#include

#include

struct point

{int x,y;

};

main()

{

struct point p1,p2; /*定义两个点*/

float dist;

printf(“\nPlease input the first point\’s value:\nx=”); /*输入第一个点*/

scanf(“%d”,&p1.x);

printf(“y=”);scanf(“%d”,&p1.y);

printf(“\nPlease input the second point\’s value:\nx=”);/*输入第二个点*/

scanf(“%d”,&p2.x);

printf(“y=”);scanf(“%d”,&p2.y);

dist=sqrt( (p2.x-p1.x)*(p2.x-p1.x)+(p2.y-p1.y)*(p2.y-p1.y) );/*计算两点距离*/

printf(“Distance of two point is %10.2f.\n”,dist);

}

2.请编写程序:将下表数据赋给结构体数组,并按照年龄从小到大顺序将它们输出到屏幕上。

姓名年龄年薪
zhangsan3828000
lisi2222000
wangwu2427000

【分析与提示】本题旨在练习结构体数组的定义、初始化及应用。对结构体数组中的内容进行排序有多种办法,鉴于本题数据较少,参考程序中使用了最原始的排序方法。

参考代码:

#include

struct emp

{

char name[20];

int age;

long yearsal;

};

main()

{

struct emp data[3]={{“zhangsan”,38,28000},

{“lisi”,22,22000},

{“wangwu”,24,27000}},tmp;

int i;

if (data[0].age>data[1].age) /*比较前两个的年龄,并在可能时交换位置*/

{tmp=data[0];data[0]=data[1];data[1]=tmp;}

if (data[1].age>data[2].age) /*比较后两个的年龄,并在可能时交换位置*/

{tmp=data[1];data[1]=data[2];data[2]=tmp;}

if (data[0].age>data[1].age) /*再次比较前两个的年龄,并在可能时交换位置*/

{tmp=data[0];data[0]=data[1];data[1]=tmp;}

printf(“\n%20s%4s%9s”,“Name”,“Age”,“Income”);

for (i=0;i<3;i++) /*输出结果*/

printf(“\n%20s,%3d,%8ld”,data[i].name,data[i].age,data[i].yearsal);

}

3.请利用教材中有关单向链表的例子,建立一个反向的链表。

【分析与提示】本题是一个非常常见的应用。其中涉及的到知识点有:建立单向链表、输出单向链表中的数据、链表的反序。其中链表的反序是教材中没有涉及到的内容。下面的代码采用的算法是:从后向前建立链表。这也是另一种建立链表的方法。教材中建立链表时,只要有一个结点存在,则表头地址就固定了,以后就在链表尾部添加新结点。而反序时首先建立的尾部结点,以后有新结点时,不断添加到其前面,即表头指针不断变化,直到无新结点时为止。此时的首地址就是链表的头地址。

参考代码:

#include

typedef struct site

{int num;

struct site *next;

} SITE;

main()

{

SITE *head1,*head2,*p1,*p;

head1=head2=NULL;

while (1) /* 建立一个链表,表头是head1 */

{

p=(SITE *)malloc(sizeof(SITE));

if (!p) {printf(“\nAllocate memory error!\n”);exit(1);}

printf(“\nPlease input data of per site(0=end):\n”);

scanf(“%d”,&p->num);

if (!p->num) break; /*如果输入数为0,则结束*/

else {

p->next=NULL;

if (!head1) head1=p; /*如果首指针为空,则为其赋值*/

else /*如果不是首指针,添加到表的结尾*/

{p1=head1;while(p1->next) p1=p1->next;p1->next=p;}

}

}

free§; /*释放最后一个无效的结点*/

printf(“\nThe original table is:\n”); /* 输出表头是head1的链表 */

p1=head1;

while (p1->num){printf(“%8d”,p1->num);p1=p1->next;}

printf(“\n”);

p1=head1; /* 表头是head1 的链表反序 */

while(p1)

{

p=p1; /*暂存首结点后,并指向下一结点*/

p1=p1->next;

if (!head2) /*如果新链表不存在,则为头指针赋值*/

{p->next=NULL;head2=p;}

else /*如果新链表已经存在,则把结点添加到其首部*/

{p->next=head2;head2=p;}

}

printf(“\nThe new table is:\n”); /* 输出反序后的链表,表头是head2 */

p1=head2;

while (p1->num){printf(“%8d”,p1->num);p1=p1->next;}

printf(“\n”);

p1=head2; /*释放链表占用的空间*/

while(p1){p=p1;p1=p1->next;free§;}

}

4. 假设有N个学生,每个学生的数据包括学号、姓名及三科成绩。要求从键盘输入各学生的数据,最后输出三科的总平均成绩及最高分学生的情况。

【分析与提示】本题是很多教材上选用的例题或习题。但算法却不尽相同。他们采用的做法一般是先输入所有学生的信息,再计算,最后再输出满足条件的记录。其实,在一个学生的信息输入完后,就已经可以计算其总分和平均分了,而且还可以对平均分进行累计。下面的参考代码就采取这种一次性的处理方式,这样可以大大提高程序运行效率。另外,输出最高分学生的详细情况部分,我们也要考虑到,这样的学生可能不只一个!所以,要在知道最高平均分的情况下,再逐个搜索的方式进行,这样才比较完美。

参考代码:

#include

#include

#define N 5

struct student

{

long studno;

char name[20];

float score[4]; /* 三科成绩及平均成绩 */

}stud[N];

main()

{

int i,j;

float average=0,sum,maxave=0,temp;

for (i=0;i<N;i++) /* 输入各学生的数据 */

{

printf(“\nPlease input the %d student\’s score:\n”,i+1);

printf(“Student number:”);scanf(“%ld”,&stud[i].studno);

getchar();

printf(“Student name:”);gets(stud[i].name);

sum=0; /* 保存每个学生总分的变量清0 */

for (j=0;j<3;j++) /* 输入的同时直接计算平均值并保存 */

{

printf(“Student score[%d]=”,j+1);

scanf(“%f”,&temp);

stud[i].score[j]=temp;

sum+=temp;

}

stud[i].score[j]=sum/3; /* 保存每个人的平均分 */

average+=stud[i].score[j]; /* 累计所有人平均分之和 */

maxave=(stud[i].score[j]>maxave)?stud[i].score[j]:maxave;/*求最大平均分*/

}

average/=N; /* 计算并输出所有学生全部课程的平均分 */

printf(“\nThe average of %d students\’ is %6.2f\n”,N,average);

printf(“\nThe best student(s\’) list:\n%student no student name score1 score2 score3 sum aver”);

for (i=0;i<N;i++) /* 输出所有平均分最高学生的完整信息 */

{

if (fabs(maxave-stud[i].score[3])<1e-6) /* 只输出平均分最高的学生信息 */

{

printf(“\n%10ld %-20s”,stud[i].studno,stud[i].name);

for (j=0;j<3;j++) printf(" %6.2f",stud[i].score[j]);

printf(” %6.2f %6.2f”,stud[i].score[j]*3,stud[i].score[j]);

}

}

}

第9章 文件

一.简答题

1.什么是文件?

【解答】文件是指存储在外部介质上的数据集合。一般分为程序文件和数据文件。

2.C语言可以处理的文件类型是什么?

【解答】 顺序存取和随机存取文件。

3.C语言文件的存取方式是什么?

【解答】 文本文件和二进制文件

4.在C语言中,文件存取是以什么为单位的,这种文件是什么?

【解答】 字符,流式文件

5.函数rewind()的作用是什么?

【解答】使位置指针重新返回文件的开头

二.编程题

1.将从键盘输入的数据存储到文件中,再将存储的文件内容在屏幕上显示(用fputc(), fgetc()函数)。

【分析与提示】先以写的方式打开文件,运用fputc( )函数把键盘录入的数据写到文件中;再以读的方式打开文件,运用fgetc( )函数从文件中读取数据显示在屏幕上。

参考代码:

#include “stdio.h”

void write_to()

{

FILE *fp;

char ch;

fp=fopen(“we”,“wb”);

if (fp==NULL)

{printf(“cannot open file”);exit(0);}

ch=getchar();

while (ch!=’\n’)

{fputc(ch,fp); ch=getchar();}

fclose(fp);

}

/* 将刚才存储的文件在屏幕上显示函数。*/

void read_in()

{

FILE *fp; char ch;

fp=fopen(“we”,“rb”);

if(fp==NULL)

{printf(“cannot open file”);exit(0);}

while(!feof(fp))

{ch=fgetc(fp);putchar(ch);}

}

void main()

{ write_to();

read_in();

}

2.编程实现两个文件中的内容合并到一个文件中,并显示出来。

#include

main()

{ FILE *fp1,*fp2;

char s[100];

if((fp1=fopen(“a1.dat”,“ab”))==NULL) /*以追加方式打开二进制文件a1*/

printf(“\nCan not open file a1.dat!”);

else

if((fp2=fopen(“a2.dat”,“rb”))==NULL) /*以只读方式打开二进制文件a2*/

printf(“\nFile a2.dat has not been found!”);

else

while(fgets(s,100,fp2)!=NULL)

fputs(s,fp1); /*读取文件a2中的内容,追加方式写到文件a1原有内容后面*/

fclose(fp1);

fclose(fp2); /*关闭a1和a2文件,防止数据丢失*/

if((fp1=fopen(“a1”,“rb”))==NULL) /*以只读方式打开二进制文件a1*/

printf(“\nFile a2.dat has not been found!”);

else

while(fgets(s,100,fp1)!=NULL) /*在屏幕上显示合并后存储在a1中的文件内容*/

printf(“\n%s”,s);

fclose(fp1);

}

3.编程:从键盘输入一行字符,把它们存入一个磁盘文件中,然后再从该文件中读出,并在屏幕上以大写方式显示出来。

#include

main( )

{ int i,flag;

char str[80],c;

FILE *fp;

fp=fopen(“text”,“w+”);

for(flag=1;flag;)

{ printf(“\n请输入字符串:\n”);

gets(str);

fprintf(fp,”%s”,str);

flag=0;

}

fseek(fp,0,0);

while(fscanf(fp,”%s”,str)!=EOF)

{ for(i=0;str[i]!=’\0’;i++)

if((str[i]>=‘a’)&&(str[i]<=‘z’))

str[i]-=32;

printf(“\n%s\n”,str);

}

fclose(fp);

}

运行结果: 请输入字符串:

I am a student ↙

I AM A STUDENT

4.从键盘输入10个整数保存到data.dat文件中,再把文件data.dat中的10个整数读出,并显示出来。

【分析与提示】先以写的方式打开文件,运用fwrite()函数把键盘录入的数据写到文件中;再以读的方式打开文件,运用fread()函数从文件中读取数据显示在屏幕上。

参考代码:

# include

# define N 10

main()

{

FILE *fp;

int data[N],i;

printf(“输入10个数:”);

for(i=0;i<N;i++)

scanf(“%d”,&data[i]);

if((fp=fopen(“data.dat”,“w+”))==NULL)

printf(“Can not open file data.dat!”);

else

{ fwrite(data,2,N,fp); fclose(fp);}

if((fp=fopen(“data.dat”,“r”))==NULL)

printf(“File b1.dat has not been found!”);

else

{fread(data,2,N,fp); fclose(fp);}

for(i=0;i<N;i++)

printf(” %d”,data[i]);

}

5.将一个磁盘文件中的信息复制到另一个磁盘文件中。

【分析与提示】运用fscanf()和fprintf()函数实现文件中信息复制。

参考代码:

#include

main()

{

FILE *fp1,*fp2;

char s[100];

if((fp1=fopen(“a1.dat”,“rb”))==NULL)

printf(“\nFile a1.dat has not been found!”);

else

fscanf(fp1,”%s”,s);

fclose(fp1);

if((fp2=fopen(“a2”,“wb”))==NULL)

printf(“\nFile a2.dat has not been found!”);

else

{fprintf(fp2,”%s”,s); printf(“\n%s”,s);}

fclose(fp1);

}

6.有4个学生,每个学生有5门课的成绩,从键盘输入数据(包括学生学号,姓名,5门课成绩),计算出平均成绩,将原有数据和计算出的平均分数存放在磁盘文件”B2″中。

【分析与提示】运用结构体数据类型存储学生成绩信息。

参考代码:

# include

struct student

{

char num[10];

char name[8];

int score[5];

float ave;

}stu[4];

main()

{

int i,j,sum;

FILE *fp;

for(i=0;i<4;i++)

{

printf(“\ninput score of student %d”,i+1);

printf(“no”);

scanf(“%s”,stu[i].num);

printf(“name: “);

scanf(“%s”,stu[i].name);

sum=0;

for(j=0;j<5;j++)

{

printf(“score %d”,j+1);

scanf(“%d”,&stu[i].score[j]);

sum=sum+ stu[i].score[j];

}

stu[i].ave=sum/5.0;

}

fp=fopen(“B2”,“w”);

for(i=0;i<4;i++)

if(fwrite(&stu[i],sizeof(struct student),1,fp)!=1)

printf(“file write error! “);

fclose(fp);

fp=fopen(“B2”,“r”);

for(i=0;i<4;i++)

{

fread(&stu[i],sizeof(struct student),1,fp);

printf(“%s,%s”,stu[i].num, stu[i].name);

for(i=0;i<5;i++)

printf(“%d”,stu[i].score[j]);

printf(“%f”,stu[i].ave);

}

}

7.统计文件中的单词个数。

【分析与提示】以空格、换行、回车符为标志判断是否为一个单词。

参考代码:

#include

main(int argc,char*argv[])

{

FILE *fp;

char ch;

int white=1;

int count=0;

if((fp=fopen(argv[1],“r”))==NULL)

{

printf(“can’t open file%s. “,argv[1]);

exit(0);

}

while((ch=fgetc(fp))!=EOF)

switch(ch)

{

case ’ ‘:

case ‘\t’:

case ‘\n’:

white++;

break;

default:

if(white)

{white=0; count++;}

}

fclose(fp);

printf(“file’%s’contains%d words. “,argv[1],count);

}

说明:

(1)一般情况下,程序中的主函数不带形参,该程序中使用了带形参的主函数,目的是为了在执行程序时,我们可以带参数,假设该程序名为countw,而要统计单词的文件名为word,要想用该程序统计word中单词的个数,可以将该程序编译形成可执行文件countw,在DOS方式执行:countw word.,这样编程的好处是可以用countw统计任一个文件中单词的个数,只要执行程序时,加带被统计文件的文件名即可。

(2)主函数形参中的argc,用于统计执行程序时,命令行参数的个数,而*argv[]是具体的命令行参数,例如:执行countw word.时,argc=2,argv[0]为countw即程序本身,而argv[1]为word。

第10章 图形与动画

一.简答题

1.文本模式下的窗口有什么特点?

【解答】文本模式下的窗口与目前我们所使用的Windows下的窗口有很大的不同:文本下的窗口大小只能以字符为单位设置,看起来跳跃性大;文本下的窗口没有边框、滚动条等可视元素,只有在操作时才能感觉边界的存在;文本下的窗口由于显示驱动程序限制,可支持的颜色数较少,不可能达到很好的色彩过渡等效果;文本方式下的窗口也不可移动,扩张大小等。

2.请解释图形模式与文本模式。

【解答】图形模式与文本模式是计算机的显示系统工作的两种不同的工作方式。在文本方式下,整个屏幕被格式化成一个个矩形块,每个矩形块内只能显示一个字符。无论是编辑还是存储,都以字符为单位,以ASCII码为存储形式。而图形工作方式则以像素点为单位,每个像素点都可独立控制显示内容。因此,图形方式显示能力比较强,内容丰富,层次较多。但处理速度比不上文本方式。

3.图形和文本模式下输出文本有什么异同?

【解答】文本模式下输出的文本默认采用系统默认的一种字体,输出时可用的坐标范围受显示模式的限制,比较有限。图形方式下输出的文本可采用多种字体和大小,且输出点坐标控制相对灵活,但控制相对于文本方式比较繁琐。

二.运行程序写结果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jfrCgw2Q-1652193328633)(media/73cddbc929323a8ed1220226f783d498.png)]1.以下程序的执行结果是 。

#include

#include

main()

{

int graphdriver=VGA; /*设置成VGA模式*/

int graphmode=VGAHI; /*采用640*480高分辨率显示模式*/

initgraph(&graphdriver, &graphmode, “”); cleardevice();

rectangle(100, 20, 150, 50); /*画矩形图*/

bar(100, 80, 200, 260); /*画画条形图*/

getch(); closegraph();

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HuBNrL9b-1652193328636)(media/32826f0411c52772fd33f623e36ec303.png)]}

【分析与提示】本题是图形部分的基础练习题,主要用来让读者进一步熟悉图形编程的步骤及相关语句。包括设置图形工作模式、初始化显示方式、关闭图形系统的方法等。

【解答】运行结果如图10-1所示。

2.以下程序的执行结果是 。

#include

#include

main()

{

int graphdriver=DETECT, graphmode, x;

initgraph(&graphdriver, &graphmode, “”); cleardevice();

ellipse(320, 100, 0, 360, 75, 50);

circle(320, 220, 50);

pieslice(320, 340, 30, 150, 50); ellipse(320, 400, 180, 360, 50, 50);

getch(); closegraph();

}

【分析与提示】本题也是一个基础练习题,用来让读者了解自动检测(DETECT)的用法。同时也包括画圆、椭圆,饼图等基础函数的应用内容。

【解答】运行结果如图10-2所示。

3.以下程序的执行结果是 。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OUOh16Qc-1652193328638)(media/2e8695b104e8efc192eb3374809f9590.png)]include “graphics.h”

main()

{int driver,mode;

driver=DETECT;

mode=2;

initgraph(&driver,&mode,””);

cleardevice();

setbkcolor(1); /*背景为兰色*/

setcolor(15); /*前景为白色*/

ellipse(300,200,0,360,80,40); /*画椭圆弧线 */

setfillstyle(1,4); /*填充模式1实填充,4红色 */

floodfill(300,200,15); /*300,200为图形的任意点,边界颜色为白色*/

getch();

closegraph();

}

【提示】本题是一个练习用填充函数,画椭圆实填充。请观察背景色、填充色及图案边界颜色。

【解答】运行结果如图10-3所示。

4.以下程序的执行结果是 。

#include

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MNN6ym5B-1652193328639)(media/b8ed5872d8bf0090affcdef926a31ed0.png)]main()

{ int i,gd,gm;

gd=VGA;

gm=VGAHI;

initgraph(&gd,&gm,””);

for(i=0;i<11;i++)

{setfillstyle(1,i);

movebar(i*50);

}

getch();

closegraph();

}

movebar(int x)

{ setviewport(x,0,639,199,1);

setcolor(5);

bar3d(10,120,60,150,40,1);

floodfill(70,130,5);

floodfill(30,110,5);

delay(60000);

clearviewport();

}

【提示】本题是一个移动方块的简单动画程序,练习通过设置视图区操作实现动画效果。

思考:可实验验证一下,不使用clearviewport()的情况,观察运行结果。

【解答】运行结果如图10-4所示。

三.编程题

1.编写程序,实现亮条式菜单的功能(类似Turbo C的某个子菜单)。

【分析与提示】亮条式菜单在DOS环境下应用非常广泛,在Windows下的下拉菜单也属此形式。这种菜单要解决下面几个问题:

(1)菜单的显示分为正常显示和反显两个状态,通用要用颜色来区分;

(2)在菜单项间移动时,要不断改变当前项的状态。即刚才选中的项要恢复成正常显示状态,新选择的项要变成选中状态,以模拟亮条的功能。

(3)菜单中要用到不少热键、快捷键等,都需要在选中某项菜单的情况下进行处理。

下面提供的参考代码采用了模块化的程序设计思想。当然,限于篇幅,某些方面也进行了删减。

参考代码:

#include

#include

#include

#define Key_DOWN 0x5000 /* 定义一组键 */

#define Key_UP 0x4800

#define Key_LEFT 0x4b00

#define Key_RIGHT 0x4d00

#define Key_ENTER 0x1c0d

#define Key_ALT_X 0x2d00

void box(int stx,int sty,int endx,int endy); /* 显示一个菜单框 */

void dispitem(char *s,int normal); /* 显示一个菜单项 */

void dispwin(char *menu[], int pos); /* 显示菜单 */

main()

{

int key,pos=0; /* 键值 */

char *menu[] ={/* 定义菜单项 */,”Load F3 “,”Pick Alt-F3 “,”New “,”Save F2 “,

“Write to “, “Directory”,“Change dir”,“OS shell”,”Quit Alt-X “};

textbackground(BLACK);

textcolor(WHITE);

clrscr();

dispwin(menu, pos);

while(1)

{

key=bioskey(0);

switch(key)

{

case Key_ALT_X: /* 如果是退出键,则结束程序 */

exit(0);

case Key_UP: case Key_LEFT: /* 向左及向上方向键,用于选择上一条菜单 */

pos–;

if (pos==-1) pos=8; /* 如果已经在第一菜单项上,上移时移到最后一项 */

dispwin(menu,pos);break;

case Key_DOWN: case Key_RIGHT: /* 向下及向右方向键,用于选择上一条菜单 */

pos++;

if (pos==9) pos=0; /* 如果已经在最后一菜单项上,下移时移到第一项 */

dispwin(menu,pos); break;

case Key_ENTER: /*回车键执行菜单功能*/

if(pos==8) exit(0);/*选中第1菜单的第9项,退出*/

break;

}

}

}

void box(int stx,int sty,int endx,int endy)

{

int i;

textbackground(LIGHTGRAY); textcolor(BLACK);

gotoxy(stx,sty); putch(0xda); /* 画┌ */

for (i=stx+1;i<endx;i++) putch(0xc4); /* 画─ */

putch(0xbf); /* 画┐ */

for(i=sty+1;i<endy;i++)

{ gotoxy(stx,i);putch(0xb3); /* 画左边和右边的│ */

gotoxy(endx,i);putch(0xb3);

}

gotoxy(stx,endy); putch(0xc0); /* 画└ */

for (i=stx+1;i<endx;i++) putch(0xc4); /* 画─ */

putch(0xd9); /* 画┘ */

}

void dispitem(char *s,int normal)/*normal为1时正常显示菜单,否则反显*/

{

if (normal)

{

textbackground(LIGHTGRAY); textcolor(BLACK);

cprintf(” “); /* 黑色显示一前导空格 */

textcolor(RED); cprintf(“%c”,*s); /* 以红色显示首字符 */

textcolor(BLACK); cprintf(“%s”,s+1); /* 以黑色显示其它字符 */

}

else

{textbackground(BLACK); textcolor(WHITE); cprintf(” %s”,s); /* 加黑显示当前项 */ }

}

void dispwin(char *menu[], int pos)

{

int i, lx=20,ly=5,rx=35,ry=15;

box(lx,ly,rx,ry); /* 调用作框函数 */

for(i=0;i<9;i++) /* 显示子菜单各项 */

{ gotoxy(lx+1,ly+i+1); dispitem(menu[i],1); }

gotoxy(lx+1,ly+pos+1); dispitem(menu[pos],0);

}

2.画出5个不同颜色的环组成一个奥运标志。

【分析与提示】奥运五环标志看起来比较简单,但用C做起来还是需要费点时间的。需要解决的问题主要是各环的色彩及环之间的交叉问题。C的填充是以边界的颜色为标志的。因此,需要在颜色方面做文章。下面的参考代码中使用了比较笨的方法,用黑色的矩形框打破交叉形成的连接边界。当然,这种填充方式并不完美,读者可以想出更好的办法来。

参考代码:

#include

void doublecircle(int x,int y); /* 画两个同心圆,参数为圆心坐标 */

main()

{

int gdriver= VGA,gmode= VGAHI, i;

initgraph(&gdriver,&gmode,””); cleardevice(); setcolor(8);

doublecircle(220,200); /* 画5个环 */

doublecircle(300,200); doublecircle(380,200);

doublecircle(260,235); doublecircle(340,235);

setcolor(0);rectangle(252,198,254,207); /* 以黑色边框画一个矩形的目的是为了突破两个环交叉的部分,使下面的填充到位,下面的矩形作用与此相同 */

setfillstyle(1,9);floodfill(185,200,8); /* 以蓝色填充 */

setcolor(0); rectangle(332,198,335,207); rectangle(290,231,297,233);

setfillstyle(1,6); floodfill(300,165,8); floodfill(297,233,8); /* 以紫色填充 */

setcolor(0); rectangle(370,231,382,233);

setfillstyle(1,4); floodfill(380,165,8); /* 以红色填充 */

setcolor(0); rectangle(225,230,228,237); rectangle(260,201,272,202);

setfillstyle(1,14); floodfill(260,270,8); floodfill(272,202,8); /* 以黄色填充 */

setcolor(0); rectangle(305,227,307,237); rectangle(340,201,353,203);

setfillstyle(1,2); floodfill(340,270,8); floodfill(353,203,8); /* 以绿色填充 */

getch(); closegraph();

}

void doublecircle(int x, int y)

{ circle(x,y,30); circle(x,y,37);}

3.用实心球实现例10.6的功能。

【分析与提示】本题与例10.6类似,只是以实心球代替了原来的圆,因此不再重复。

参考代码:

include

#include

#include

void main()

{

int driver=VGA, mode=VGAHI, i;

initgraph(&driver,&mode,””);

line(0,330,639,330); /*画水平线和斜线,表示一个平面*/

for (i=8;i<=632;i+=8)

{line(i,330,i-4,340); }

setfillstyle(1,15);

for (i=1;i<=18;i++) /*分段画出一个正椭圆球*/

{sector(320,50,(i-1)*20,i*20+2,30,30); delay(40000); }

for (i=50;i<=300;i+=10) /*让圆球下落*/

{

setfillstyle(1,0); setcolor(0); pieslice(320,i-10,0,359,30);/*隐去上一个圆球*/

setfillstyle(1,15); setcolor(15); pieslice(320,i,0,359,30); /*在下面画一个新圆球*/

delay(40000);

}

for (i=1;i<=4;i++) /*圆球变为真正的椭圆球*/

{

setfillstyle(1,0);setcolor(0);fillellipse(320,300+(i-1)*2,30,30-(i-1)*2);/*隐去上一个椭圆球*/

setfillstyle(1,15); setcolor(15);fillellipse(320,300+i*2,30,30-i*2);/*在下面画一新椭圆球*/

delay(40000);

}

for (i=4;i>=1;i–) /*椭圆变为圆球*/

{

setfillstyle(1,0); setcolor(0);fillellipse(320,300+i*2,30,30-i*2); /*隐去上一个椭圆球*/

setfillstyle(1,15); setcolor(15); /*在上面画一个新椭圆球*/

fillellipse(320,300+(i-1)*2,30,30-(i-1)*2);delay(40000);

}

getch(); closegraph();

}

4.为例10.7图中的各部分组成加上文字说明。

【分析与提示】本题的关键点是控制输出文字的位置,需要通过多次实验,积累经验后才能比较准确地定位。

参考代码:

#include”graphics.h”

main()

{

int driver=VGA,mode=VGAHI;

int xcenter,ycenter,r,x,y;

initgraph(&driver,&mode,””);cleardevice();

xcenter=300; ycenter=200; r=100; /* 中心点坐标及饼图半径*/

settextstyle(0,HORIZ_DIR,1); outtextxy(220,60,“This is a Pie Chart”);/* 饼图标题 */

setfillstyle(1,RED);pieslice(xcenter,ycenter,0,40,r);/* 饼图第一份及标题 */

outtextxy(400,165,“11.1%”);

setfillstyle(10,GREEN);pieslice (xcenter,ycenter,40,90,r);/* 饼图第二份及标题 */

outtextxy(340,100,“13.9%”);

setfillstyle(9,YELLOW);pieslice(xcenter,ycenter,90,120,r);outtextxy(260,90,“8.3%”);

setfillstyle( 7,BLUE);pieslice (xcenter,ycenter,120, 170,r);outtextxy(180,130,“13.9%”);

setfillstyle(2,RED);pieslice(xcenter,ycenter,170,220,r);outtextxy(160,220,“13.9%”);

setfillstyle(3,RED);pieslice(xcenter,ycenter,220,280,r);outtextxy(240,300,“16.7%”);

setfillstyle(6,RED);pieslice(xcenter,ycenter,280,320,r);outtextxy(340,295,“11.1%”);

setfillstyle(8,RED);pieslice(xcenter,ycenter,320,360,r);outtextxy(395,230,“11.1%”);

getch ();closegraph ();

}

5. 编写程序绘制出一面飘动的红旗。

【分析与提示】

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WnuuIHxH-1652193328641)(media/822db78c42a71e2e96561c4d200d775b.png)]本程序利用正弦三角函数和写点、画线及填充功能,首先画出两幅旗帜飘动时的两个状态图(状态图越多,效果越逼真),并使用相关函数以图像方式保存在内存中。然后,通过在同一个位置不断循环显示它们,以模拟实现旗帜飘动的效果。

参考代码:

#include

#include

#include

#include

void main()

{

int driver=VGA, mode=VGAHI; /*定义图形标准*/

char ch[20], *p1,*p2; /*存储图形所在位置的指针*/

int size, stx=200,endx=450,sty=50,endy=200; /*旗帜的标准大小*/

void horline(int x0, int y0, int x1,int a, int k); /*画水平曲线函数*/

void verline(int x0, int y0, int y1,int a, int k); /*画垂直曲线函数*/

initgraph(&driver,&mode,””); /*初始化图形系统*/

setcolor(14); /*线条颜色为黄色*/

horline(stx,sty,endx,0,2); /*画旗帜上面的水平曲线*/

verline(endx,sty,endy,10,3); /*画旗帜右边的垂直曲线*/

horline(stx,endy,endx,0,2); /*画旗帜下面的水平曲线*/

setfillstyle(1,14); bar(stx-3,sty-5,stx-1,endy+150); /*画旗帜左边的旗杆*/

setfillstyle(1,4); floodfill(stx+50,sty+50,14); /*以红色填充旗帜*/

size=imagesize(stx,sty-5,endx+5,endy+5); /*保存旗帜的这种状态于p1处*/

p1=(char *)malloc(size); getimage(stx,sty-5,endx+5,endy+5,p1);

setfillstyle(1,0); floodfill(stx+50,sty+50,14);/*取消旗帜的填充,变为填充黑色*/

setcolor(0); horline(stx,sty,endx,0,2); /*把所有旗帜的边线变为黑色*/

verline(endx,sty,endy,10,3); horline(stx,endy,endx,0,2);

setcolor(14); /*再画另一种旗帜的状态,边线为黄色*/

horline(stx,sty,endx,0,4);

verline(endx,sty,endy,10,6); horline(stx,endy,endx,0,4);

setfillstyle(1,4); floodfill(stx+50,sty+50,14); /*旗帜内部依然填充为红色*/

size=imagesize(stx,sty-5,endx+5,endy+5); /*保存此种旗帜的图形于p2处*/

p2=(char *)malloc(size); getimage(stx,sty-5,endx+5,endy+5,p2);

while(!kbhit())

{

putimage(stx,sty-5,p1,0); delay(65000); /*显示一种状态的旗帜*/

putimage(stx,sty-5,p2,0); delay(65000); /*显示另一种状态的旗帜*/

}

getch(); /*暂停,按任一键结束*/

free(p1);free(p2); closegraph(); /*释放占用的内存,关闭图形系统*/

}

void horline(int x0,int y0, int x1, int a, int k)

{

int i,rel,fcolor=getcolor(); /*得到当前颜色*/

for(i=x0;i<x1;i++) /*从左到右画水平曲线*/

{

rel=(int)(5*sin((i*k+a)*3.141593/180)); /*最大垂直飘扬偏差为5像素*/

putpixel(i,rel+y0,fcolor); /*逐点画出此水平曲线*/

}

moveto(i,rel+y0); lineto(x1,y0); /*连接最后的线段,防止可能出现的断线*/

}

void verline(int x0,int y0,int y1,int a,int k)

{

int i,rel,fcolor=getcolor(); /*得到当前颜色*/

for(i=y0;i<y1;i++) /*从上到下画垂直曲线*/

{

rel=(int)(5*sin((i*k+a)*3.141593/180));/*最大水平飘扬偏差为5像素*/

putpixel(rel+x0,i,fcolor); /*逐点画出此垂直曲线*/

}

moveto(rel+x0,i); lineto(x0,y1); /*连接最后的线段,防止可能出现的断线*/

}

6.眼睛可以转动的小猫。

【分析与提示】本题的主要是练习用画圆、画圆弧、画直线及填充函数,来画一个自己喜欢的图形。关键点是控制输出的位置,需要通过多次调整,熟练后就能比较准确地定位。

#include

#include

#include

#define PATH “c:\\tc”

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ywozVnqb-1652193328642)(media/bcdea6e508a249104520e0f4d6313820.png)]#define PI 3.1415926

main()

{int gdriver=VGA,gmode=VGAHI;

int i,a,b,c,d;

initgraph(&gdriver,&gmode,PATH);

ellipse(288,164,0,360,96,72);

circle(240,176,18);

circle(320,176,18);

circle(250,176,6);

circle(310,176,6);

circle(280,200,10);

floodfill(240,176,WHITE);

floodfill(320,176,WHITE);

floodfill(280,200,WHITE);

arc(250,90,160,220,60);

arc(250,90,172,220,50);

arc(180,140,30,85,70);

arc(180,140,30,70,60);

arc(300,90,330,15,80);

arc(300,90,335,5,70);

arc(388,130,95,150,60);

arc(388,130,110,150,50);

floodfill(360,85,WHITE);

floodfill(220,90,WHITE);

arc(285,200,224,315,46);

floodfill(280,242,WHITE);

arc(280,310,325,65,85);

arc(350,300,270,350,60);

arc(350,300,265,0,70);

arc(415,307,45,225,8);

arc(280,300,290,312,95);

arc(280,280,120,200,50);

arc(230,330,80,155,30);

line(203,313,218,345);

arc(230,330,235,330,20);

line(248,340,255,330);

arc(265,340,330,135,13);

line(245,380,278,346);

arc(275,380,180,270,30);

arc(310,430,89,147,40);

line(340,210,380,215);

line(350,220,400,225);

line(255,220,200,228);

line(245,230,190,238);

for(i=0;i<=2*PI;i++)

{circle(250,176,6);

circle(310,176,6);

floodfill(250,176,WHITE);

floodfill(250,176,WHITE);

setcolor(BLACK);

a=240+10*cos(i);

c=320+10*cos(i);

b=176-10*sin(i);

d=176-10*sin(i);

circle(a,b,6);

circle(c,d,6);

floodfill(a,b,BLACK);

floodfill(c,d,BLACK);

setcolor(WHITE);

getch();

}

}

要求:读懂该程序,将小猫的左眼珠的黑点位置找到并补画上。仿照该例题思路,画出一个自己喜欢的小动物或山水画。由于篇幅,我们下面选了4幅学生用C语言所编写的动画图形,使人看起来赏心悦目。我们自己也动手作出1~2幅静态或动画图形作品。