C语言程序设计复习资料及习题(3)
单元七 函数的使用
单元总结提升
在本单元中,如何使用自定义函数是核心内容。通过本单元的学习,我们应该知道:
1. 函数是构成C程序的基本单位,函数的使用为模块化程序设计奠定了基础。从用户使用的角度,函数分为 库 函数、 自定义 函数两种。
2. 库函数的使用包括 头文件包含 和 库函数调用 两个环节;用户自定义函数的使用包括 函数声明 、 函数定义 和 函数调用 三个环节。
3. 从函数的外观形式看,函数分为 有参 函数、 无参 函数两种。当主调函数调用无参 函数时,不需要向这些函数传递参数;当主调函数调用 有参 函数时,需要传递参数。
4. 用户自定义函数的一般形式为:
函数返回值类型 函数名(形式参数列表) //函数首部
{ 函数体;
}
其中第一行称为 函数首部 ,大括号“{}”括起来的部分称为 函数体 ,对于有返回值的函数,函数体中要包括 return 语句。
5.函数首部也称为函数原型,用函数原型声明函数时,形参名可以省略不写,而只写形参的类型,但形参的 类型 和 数量 必须与函数首部保持一致。
6.函数要先声明,然后才能使用,函数声明在程序中的位置有以下几种情况:(1)函数声明写在主调函数的外部,这时的函数声明为全局声明。(2)函数声明写在主调函数的说明语句中,这时的函数声明为局部声明。(3)函数的定义出现在主调函数之前,则函数声明可以省略。
7.函数的调用形式为:函数名(实际参数列表)。若调用无参函数,则实参为空;若调用有参函数,则在()内写出与形参类型、数量一致的实参。对于有参函数,函数调用过程中存在着参数传递的问题,参数传递有两种情况,其一为 值传递,其二为 地址传递。
8.函数在函数体中出现了对自身调用的语句,就称为函数递归调用。使用递归方法解决问题的关键是如何找出 递归关系 ,以及找出递归调用的 终止条件 。
9.带参宏定义的一般形式为: #define 宏名(形参列表) 字符串 。通常用带参数的宏定义代替简单公式型函数。
10.函数的存储类型有static和extern两种。 extern 型函数称为“外部函数”,可以被其他编译单位中的函数调用; static 型函数称为“内部函数”,只能被本编译单位的函数调用。
11.程序中变量的使用范围称为变量的作用域,每个变量都有自己的作用域。按照作用域的范围可分为两种: 局部变量 和 全局变量 。
12.变量的存储方式可分为“动态存储”和“静态存储”两种。动态存储变量包括
auto 和 regiest 两种类型;静态存储变量包括 static 和 extern 两种类型。静态存储变量若没有初始化,则默认初始值为 0 。static类型变量的值具有继承性,即本次调用的初值是上次调用结束时变量的值。
单元练习
一.选择题
1.关于使用函数的目的,以下不正确的说法是( )。
A.提高程序的执行效率 B.提高程序的开发效率
C.减少程序文件所占内存 D.提高程序可读性
2.以下正确的函数首部是( )。
A.void fun(int x,int y) B.void fun(int x;int y)
C.void fun(int x,y) D.void fun(x,y)
3.设函数fun的定义形式为:
void fun(char ch, float x) { ......}
则以下对函数fun的调用正确的是( )。
A.fun("abc",3.0); B.t=fun('D',12.3);
C.fun('65',3.7); D.fun(65,65);
4.关于函数的实参和形参,以下正确的说法是( )。
A.实参和对应的形参各占用独立的存储单元
B.实参和对应的形参共同占用同一存储单元
C.只有当实参与形参重名时才共同占用存储单元
D.形参是虚拟的,不占用存储单元
5.当调用函数时,实参是一个数组名,则向函数传递的是( )。
A.数组的长度 B.数组的首地址
C.数组的每一个元素的地址 D.数组的每一个元素的值
6.将一个函数指定为static存储类别后,该函数将( )。
A.既可以被同一源文件中的函数调用,也可以被其他源文件中的函数调用
B.只能被同一源文件中的函数调用,不能被其他源文件中的函数调用
C.只能被其他源文件中的函数调用,不能被同一源文件中的函数调用
D.既不能被同一源文件中的函数调用,也不能被其他源文件中的函数调用
7.以下叙述正确的是( )。
A.全局变量的作用域一定比局部变量的作用域作用范围大
B.静态static类型变量的生存期贯穿于整个程序的运行期间
C.函数的形参都属于全局变量
D.未在定义语句中赋初值的auto变量和static变量的初值都是随机值
二.填空题
1.假设已有#define M(r) r*r,则语句printf(“%d”,M(2+3));的执行结果为 。
2.以下程序输出结果为 。
#include
void fun(int x,int y)
{ x=x+y;y=x-y;x=x-y;
printf("%d,%d\n",x,y);
}
void main()
{ int x=2,y=3;
fun(x,y);
printf("%d,%d\n",x,y);
}
3.以下程序输出结果为 。
#include
int a,b;
void fun()
{ a=10;b=20;
}
void main()
{ int a=3,b=9;
fun();
printf("%d,%d\n",a,b);
}
4.以下程序输出结果为 。
#include
int f( ) //定义f函数,a为形参
{int b=0; //定义b为自动变量
static int c=3; //定义c为静态局部变量
b=b+1;
c=c+1;
return b+c;
}
void main( )
{int a1,a2;
a1=f();
a2=f();
printf("%d,%d",a1,a2);
}
5.以下程序输出结果为 。
#include
int fun(int n)
{ if(n==1) return 1;
else return fun(n-1)+1;
}
void main()
{ int i,j=0;
for(i=1;i<3;i++)
j+=fun(i);
printf("%d\n",j);
}
6.以下程序输出结果为 。
#include
void fun(int a[ ], int n)
{ for(int i=0;i<n;i++)< p="">
if(a[i]>0) a[i]*=2;
}
void main()
{ int b[5]={1,2,3,4,5};
fun(b,5);
for(int i=0;i<5;i++)
printf("%d\t",b[i]);
}
习题答案:
一.选择题
1.A 2.A 3.D 4.A 5.B 6.B 7.B
二.填空题
1.11
2.3,2
2,3
3.3,9
4.5,6
5.3
6.2 4 6 8 10
单元八 指针的使用
单元总结提升
在本单元中,对指针的理解,以及利用指针访问不同形式的数据是核心内容。通过本单元的学习,我们应该知道:
1. 内存地址就称为指针。C语言允许用一个变量来存放指针,这种变量称为指针变量,而指针变量的值就是某个内存单元的地址。
2. 定义指针变量的一般格式为: 类型标识符 *指针变量名 ,其中:
(1)“指针变量名”前面的“*”,表示该变量是指针变量,不能省略。
(2)“类型标识符”表示该指针变量所指向的变量的数据类型。
(3)当一个指针变量已确定指向某类型的变量时,不能再指向另一种类型的变量。
3.指针变量被赋值后即可引用,引用指针变量的一般方法为: *指针变量名 。
4.指针和数组有着密切的关系,任何通过控制数组下标实现的对数组的操作,都可用指针来实现。要通过指针操作数组,首先要建立指针变量与数组之间的关系,然后才能通过指针变量访问数组元素。若有语句段: int a[10]; int *p; p=a;,则对于数组元素的访问方式有 a[i]、 *(p+i) 、 p[i] ,对数组元素地址的表示方式有 a+i 、 p+i 、 &a[i] 。
5.数组名代表数组的首地址,利用函数处理一维数组数据时,函数之间的参数传递为 数组首地址 。将数组的首地址作为实参传递给函数的形参以后,实参数组和形参数组其实是同一段内存中的数据。
6.字符串是存放在某存储区域的一串字符序列,可通过字符数组和字符指针两种方式操作字符串。
7.函数返回值可以是地址(指针类型),返回值为地址的函数定义形式为:
通过本单元的学习,应明确地址和指针的关系,掌握使用指针访问内存数据的基本方法。
单元练习
一.选择题
1.假设整型变量a的值是12,a的地址是2200,若想使整型指针变量p指向a,以下赋值正确的是( )。
A.&a=2200; B.*p=12; C.*p=2200; D.p=&a;
2.若有定义int *p,m=5,n;,以下正确的程序段是( )。
A.p=&n; scanf"%d",&p); B.p=&n; scanf("%d",*p);
C.scanf("%d",&n); *p=n; D.p=&n; *p=m;
3.以下合法的定义是( )。
A.str[]={"China"}; B.char *p="China";
C.char *p; strcpy(p, "China"); D.char str[13]; str[]="China";
4.若有定义int a[ ]={1,3,5,7,9,11}, *p=a;,则能够正确引用该数组元素的是( )。
A.a B.a[6] C.*(p--) D.*(--p)
5.以下程序运行结果为( )。
#include
void main( )
{
char a[]="Language",b[]="programe";
char *p,*q;
int k;
p=a;q=b;
for(k=0;k<8;k++)
if(*(p+k)==*(q+k))
printf("%c",*(p+k));
}
A.gae B.ga C.Language D.programe
二.填空题
1.给出以下程序的执行结果 。
#include
void main( )
{
int *p1,*p2,*p;
int a=10,b=12;
p1=&a;p2=&b;
if(a<b)< p="">
{p=p1;p1=p2;p2=p;}
printf("%d,%d,",*p1,*p2);
printf("%d,%d",a,b);
}
2.以下程序的功能是把数组元素的最大值放入a[0]中,则条件表达式应为 。
#include
void main( )
{
int a[10]={6,7,2,9,5,10,4,3,8,1};
int *p=a,i;
for(i=0;i<10;i++,p++)
if( ) *a=*p;
printf("%d",*a);
}
3.以下程序的输出结果是 。
#include
void main( )
{
int a[2][3]={{1,2,3},{4,5,6}};
int m,*ptr;
ptr=&a[0][0];
m=(*ptr)*(*(ptr+2))*(*(ptr+4));
printf("%d",m);
}
4.下列函数功能是计算str所指字符串的长度,并作为函数值返回。请填空。
int mystrlen(char *str)
{
char *p;
for(p=str; !='\0';p++);
return( );
}
5.以下程序中,函数scmp的功能是返回形参指针s1和s2所指字符串中较小字符串的首地址。试问当程序运行时依次输入:abcd、abba和abc三个字符串,则输出结果为 。
#include
#include
char *scmp(char *s1,char *s2)
{ if(strcmp(s1,s2)<0)
return(s1);
else
return(s2);
}
void main( )
{ int i;
char string[20],str[3][20];
for(i=0;i<3;i++)
gets(str[i]);
strcpy(string,scmp(str[0],str[1]));
strcpy(string,scmp(string,str[2]));
printf("%s\n",string);
}
习题答案:
一.选择题
1.D 2.D 3.C 4.C 5.A
二.填空题
1.12,10,10,12
2.*p>*a
3.15
4.*p p-str
5.abba
单元九 结构类型的使用
单元总结提升
在本单元中,结构类型数据的含义、结构类型的描述方法、结构类型数据的基本操作是核心内容。通过本单元的学习,我们应该知道:
1.结构类型数据使用的基本步骤为 结构类型说明、 结构类型变量定义 和 结构变量使用 。
2.结构类型说明的关键字为 struct 。结构类型变量所占用内存字节数为结构变量所包含的各个成员变量所占字节数之和 。
3.若定义了一个结构变量和一个指向结构变量的指针,则可以用以下三种形式访问结构成员:
(1)利用结构变量与成员运算符相结合,基本格式为: 结构变量.成员名 。
(2)利用结构指针与成员运算符相结合,基本格式为: (*结构指针).成员名 。
(3)利用结构指针与指向运算符相结合,基本格式为: 结构指针->成员名 。
4. 结构变量不能作为一个整体进行输入和输出,但结构变量作为一个整体可以被复制、赋值、传递参数,以及作为函数返回值。当用结构变量作函数参数进行整体传送时,要将全部成员逐个传送,特别是成员为数组时,将会使传送的时间和空间开销很大,所以一般不将结构变量作为函数参数,而用结构指针变量作函数参数。这时由实参向形参传递的只是地址,从而减少了时间和空间的开销。
通过本单元的学习,应明确结构类型的数据特点,掌握结构类型数据描述和操作的基本步骤和方法。
单元练习
一.选择题
1.以下描述正确的是( )。
A.结构类型中的成员可以是结构类型
B.结构类型的成员不能是指针类型
C.结构类型中各成员共享同一个内存单元
D.在结构类型说明后就立即分配内存空间
2.已知如下定义的结构类型变量,若有p=&data,则对data中的成员a的正确引用是( )。
struct sk
{ int a;
float b;
}data,*p;
A.(*p).data.a B.(*p).a C.p->data D.p.data.a
3.若有如下定义,则下列输入语句正确的是( )。
struct stu
{ int a;
int b;
}student;
A.scanf(“%d”,&a); B.scanf(“%d”,&student);
C.scanf(“%d”,&stu.a); D.scanf(“%d”,&student.a);
4.有如下结构类型说明和变量定义,则操作语句正确的是( )。
struct worker
{ int num;
char name[10];
char sex;
int age;
} s1,s2,t;
A.if(s1.age>s2.age) {t=s1; s1=s2; s2=t; }
B.s1={1101,”zhangsan”,’f’,28};
C.gets(&s1.name);
D.printf(“%d,%s,%c,%d”,s1.num,s1.name,s1->sex,s1->age);
5.以下叙述正确的是( )。
A.结构类型说明与结构变量的含义一样,都可以用来存放数据。
B.对于不同类型的数据,若想形成一个有机的整体,可以使用结构类型。
C.可以使用“==”或“!=”对同一个结构类型的两个变量进行整体比较。
D.同一结构类型中的成员变量名称可以相同。
二.填空题
1.若有如下定义:
struct student
{ int num;
char name[12];
double score;
}stu;
则结构类型的关键字是 ,用户定义的结构类型名是 ,用户定义的结构变量是 。
2.若有如下定义:
struct worker
{ int num;
char name[12];
char sex;
int age;
}s,*p;
则sizeof(struct worker)的值是 ,变量s所占内存字节数是 ,变量p所占内存字节数是 。
3.若有如下定义:
struct num
{ int a;
int b;
float f;
}n={1,3,5.0};
struct num *pn=&n;
则表达式pn->b/n.a*pn->b的值是 ,表达式(*pn).a+pn->f的值是 。
4.结构数组中存有三个人的姓名和年龄,要输出年龄最大的人的姓名和年龄。将程序补充完整。
#include
struct man
{
char name[20];
int age;
}person[ ]={"Zhanghua",20,"Liuyang",25,"Sunpeng",19};
void main( )
{
struct man *p,*q;
int old=0;
for(p=person;p ;p++)
if(oldage) {q=p; ; }
printf("%s %d",q->name,q->age);
}
5. 下面程序的功能是从键盘上输入5个人的年龄、姓名和性别,然后输出。将程序补充完整。
#include
struct man
{
char name[20];
int age;
char sex[4];
};
void data_in(struct man *p,int n)
{
struct man *q= ;
for( ;p<q;p++)< p="">
{
printf("name;age;sex\n");
scanf("%s%d%s", , , );
}
}
void data_out(struct man *p,int n)
{
struct man *q= ;
for( ;p<q;p++)< p="">
printf("%s;%d;%s\n",p->name,p->age,p->sex);
}
void main( )
{
struct man person[5];
data_in(person,5);
data_out(person,5);
}
习题答案:
一.选择题
1.A 2.B 3.D 4.A 5.B
二.填空题
1.struct student stu
2.21 21 1 (上机测试)
3.9 6.000000
4.page;
5.p+n p->name,&(p->age),p->sex p+n
单元十 文件操作
单元总结提升
在本单元中,如何打开文件、如何读写文件以及如何关闭文件是核心内容。通过本单元的学习,我们应该知道:
1.C语言对文件的操作是通过文件指针实现的,文件指针是系统定义好的结构类型,名称为 FILE ,该类型已在头文件stdio.h中定义,对文件进行操作时,用该类型直接定义文件指针变量即可。定义形式为: FILE *文件指针变量名; 。
2.对文件的操作过程及相应的文件操作函数为:
第一步: 打开文件 ,相应的函数为 fopen() 。
第二步: 读写文件 ,相应的函数为 fputc()/fgetc()等 。
第三步: 关闭文件 ,相应的函数为 fclose() 。
通过本单元的学习,应理解文件指针FILE的含义,重点掌握利用文件指针操作文件的方法,以及文件操作函数的使用方法。
单元练习
一.选择题
1.设fp为FILE类型的指针,要以只写的方式打开文件d:\data\file.txt,正确的语句是( )。
A.fp=fopen(“d:\data\file.txt”,”w”);
B.fp=fopen(“d:\\data\\file.txt”,”w”);
C.fp=fopen(“d:\data\file.txt”,”r”);
D.fp=fopen(“d:\\data\\file.txt”,”r”);
2.执行fopen函数时发生错误,则函数的返回值是( )。
A.地址值 B.NULL(0) C.1 D.EOF(-1)
3.当正确执行了文件关闭操作时,fclose函数的返回值是( )。
A.-1 B.true C.0 D.1
4.rewind函数的作用是( )。
A.使位置指针重新返回文件的开头
B.使位置指针指向文件所要求的特定位置
C.使位置指针从新返回文件的末尾
D.使位置指针自动移到下一个字符位置
5.以下程序想要把键盘输入的字符写到文件data.txt中,直到输入“*”为止,但程序有错误,出错的原因是( )。
#include
void main()
{
FILE *fp;
char ch;
fp=fopen("data.txt","w");
ch=getchar();
while(ch!='*')
{ fputc(fp,ch);
ch=getchar();
}
fclose(fp);
}
A.函数fopen调用形式错误
B.函数fclose调用形式错误
C.函数fputc调用形式错误
D.函数getchar()调用形式错误
二.填空题
1.以下程序功能是:用变量count统计文件中字符的个数。请将程序补充完整。
#include
#include
void main()
{ FILE *fp;
long count=0;
if((fp=fopen("letter.dat", ))==NULL)
{ printf("不能打开文件.");
exit(0);
}
while(fgetc(fp)!=EOF) ;
printf("文件中的字符个数为%ld.\n",count);
fclose(fp);
}
2.以下程序的功能是:找出文件file.txt中所有的整数。文本文件file.txt中存有一系列整数,各整数之间以空格、Tab符、回车符分隔。程序中用数组b[]存储不同的整数,变量k为已存入数组b中的不同整数的个数,并假定文件的不同整数个数不超过1000个。请将程序补充完整。
#include
#include
#define N 1000
void main()
{ FILE ;
int b[N],d,i,k;
if((fp= )==NULL)
{ printf("不能打开文件.");
exit(0);
}
k=0;
while(fscanf( )==1)
{ b[k]=d;
for(i=0;b[i]!=d;i++);
if(i==k) k++;
}
;
}
习题答案:
一.选择题
1.B 2.B 3.C 4.A 5.C
二.填空题
1."r" count++
2.#include
#include
#define N 1000
void main()
{ FILE *fp ;
int b[N],d,i,k;
if((fp= fopen("file.txt","r") )==NULL)
{ printf("不能打开文件.");
exit(0);
}
k=0;
while(fscanf(fp,"%d",&d )==1)
{ b[k]=d;
for(i=0;b[i]!=d;i++);
if(i==k) k++;
}
fclose(fp) ;
}
