1 外部函数是指________的函数,它可以在_________中被调用。
【分析】当存储类型选用“extern”时,所定义的函数称为外部函数。外部函数可以在其他编译单位中调用(需要对这个函数进行说明)。
【答案】存储类型是“extern”的函数
所有对该函数进行说明过的编译单位
2 假定在同一个编译单位中,函数a()调用了函数b(),则对函数b()不需要说明的情况有下列两种:_____________和________________。
【分析】教材中有明确答案(p116)。
【答案】b()函数的定义地点在a()函数定义地点之前
b()函数的数据类型是int或char
3 在函数间传递数据的四种方式中,不能把被调函数的数据带回到主调函数的是()
①值传递 ②地址传递 ③返回值传递 ④全局外部变量
【分析】值传递方式是利用形式参数和实际参数结合来进行数据传递的一种方式,它是在调用函数时,将实际参数的值传递给形式参数,函授调用结束后,并不将形式参数的当前值传回实际参数。
【答案】①
4 如果函数定义时,形式参数是整型变量,则调用该函数时,实际参数不可以是()
①整型常量 ②字符型变量
③指向整型变量的指针型变量 ④整型表达式
【分析】当形式参数是变量时,实际参数可以是数据类型相同的表达式(常量、变量是表达式的特例),因此,备选答案①④显然是正确的,即不符合题意。而字符型数据可以看成整型数据,所以字符型变量可以当作整型变量,因此备选答案②也是正确的,即不符合题意。只有备选答案③是错误的,因为指针型变量不是整型变量,本题答案应该选取③。
请读者注意,如果使用“*指针型变量”侧是正确的。
【答案】③
5 若函数a()调用了函数b(),而函数b()又调用了函数a(),这样的调用称为_________________调用。
【分析】一般来说,只要是函数调用了自己,则称这样的函数调用为递归调用。如果函数f()调用了函数f(),我们称这样的递归调用为“直接递归调用”;如果函数f()调用了函数g(),而函数g()又调用了函数f(),这样的递归调用称为“间接递归调用”。
【答案】递归(或间接递归)
6 下列表达式中,不能判断字符型变量ch中的字符是英文字母(是则表达式值为非0、否则表达式值为0)的表达式是()
①ch>='A'&&ch<='Z'::ch>='a'&&h<='z'
② toupper(ch)>='A'&&toupper(ch)<='Z'
③ isalpha( ch)
④ !(isdigit(ch))
【分析】备选答案①中的逻辑表达式的含义是:当ch中的字符是大写字母或者小写字母时,结果为1,否则结果为0,该答案不符合题意。备选答案②中使用了系统函数toupper(),该函数功能是将参数对应的字符换成大写字母(如果参数对应的字符不是英文字母则不改变),答案中的逻辑表达式含义是:转换成大写后如果落在'A'到‘Z'之间则值为1,否则值为0。该答案也不符合题意。备选答案③中使用了系统函数isalpha(),该函数功能是判断参数对应的字符是否是英文字母,是则返回非0;否则返回0。显然该答案也不符合题意。只有备选答案④是符合题意的。分析这个答案中的表达式,其中用到了系统函数isdigit(),该函数的功能是判断参数对应的字符是不是数字字符,是则返回非 0,否则返回 0,该答案中的表达式是“! isdigit(ch)”,即 ch中不是数字字符则返回1,否则返回0,因此,该表达式不能判断ch中是否英文字母,所以本题答案应选④。
【答案】④
7 函数调用malloc(sizeof(long)* 2)的功能是申请____________个字节的内存;这批内存的首地址是____________________。
【分析】 系统池数malloc(形参)的功能是申请“形参”个字节的内存,函数的返回值就是这批内存的首地址。题目中的参数是“snzeof(long)*2”,sizeof(long)是长整型数据的字节数,其值为 4。而函数malloc(sizeof(long)* 2)调用的参数是 sizeof(long)* 2,其值为 8。
【答案】 8
函数调用的返回值
8 下列函数定义中,正确的是()
①int f(int x,y) ② int *f(int x,int*y)
{return(y);} { return(y);}
③ int f( x,*y) ④ void f( int x;)
int x, int y; {return(x);}
{return;}
【分析】分析备选答案①:形式参数表不正确,两个整型变量应该写成 int x,int y。分析备选答案②:这是一个指针型函数,函数返回值是指向整型数据的指针值,形式参数表也是正确的,在函数体中有带返回值的返回语句,且返回值就是指向整型数据的指针变量值,该答案符合题意。分析备选答案③:形式参数表中的int *y是错误的,应该为int y;这样形式参数说明中的 int y也是错误的,应该写成 int *y;函数体中的返回语句也是错误的,因为这个函数是有返回值的函数。分析备选答案④:形式参数表中最后的“分号”不能有 ;函数体中的返回语句只能用“ return;”,因为该函数是无返回值的函数。
【答案】②
9 已知梯形法求积分y=|a f(x)dx的公式如下:
n-1
y=((f(a)+f(b))/2+∑f(a+ih)) )h
i=1
其中的n是积分区间等分的间隔数目(n是任选的,越大则结果精度越高);其中的h=(b-a)/n。
函数y()是计算并返回 |a(sin(x)+cos(x))dx积分值的,请填写函数中缺少的句。
# include"math.h"
double y(a,b,n)
double a, b;
int n;
{ double sum,h;
____________________
int i;
h=(b-a)/n;
sum=(f(a)+f(b))/2;
for(i=l;i<n;i++)
sum+= f(a+ i*h);
____________________
return( sum);
}
double f(x)
double x;
{ double y;
y=(sin(x)+cos(x));
return(y);
}
【分析】阅读程序清单可以看出函数 f()是求函数 f(X)= Sin()+ COS()值的,这个函数是完整的,没有要填写的语句。再看函数y(),这个函数是求积分的函数,其中有两个空白处。第1个空白处的前后都是数据定义语句,所以这个空白只能填写数据定义语句(包括数据、函数的说明语句)。再从函数体中使用的数据来看,凡是用到的变量要么是形式参数(a、b、n),要么是定义的局部变量(sum、h、i),不存在没有定义的变量,对于这种情况来说,需要考虑函数体中调用的函数是否需要说明。从函数体中看出,要调用的函数是f(),这个函数的定义在调用处之后出现,并且不是int或char型(是double型),所以这儿的空白要填写对函数f()的说明。第2个空白处是在循环语句之后。分析这段程序,循环前先计算出h=(b-a)/n,再计算y=(f(a)+f(b)/2)(程序中用的变量是sum)。接下来的次数
n-1
型循环显然是计算 ∑ f(a+ih),并且加到变量 sum中。
i=1
从题目给出的公式中可以看出,现在变量sum中的值还不是积分值,需要再乘以h,第 2个空白处就是完成这项工作的,所以应该填写的语句是 sum= sum* h;,或者 sum*=h;。
【答案】double f();
sum=sum*h; 或者 sum*=h;
10 求两个正整数的最大公约数的算法通常使用“辗转相除法”。设有两个正整数m、n,求它们的最大公约数的算法如下:
①若m<n,则交换m和n(保证m大于n)。
②计算m/n的余数r。
③若r不等于0,则令m=n、n=r,转第②步继续执行;
否则,算法结束,n就是最大公约数。
下面就是用“辗转相除法'才出并返回m、n最大公约数的函数fmn(),请填写清单中缺少的语句。
int fmn( m, n)
int m, n;
{ int r;
if(m<n )
{r=m;m=n;n=r;}
if(n==0)
return(m);
do{_________________
if(r!= 0)
{ m=n; n=r;}
}while(r!=0);
return(n);
}
【分析】由于算法步骤已经给出,按照算法来理解程序就比较简单。函数体开始的单分支语
句是确保m值是大于n值的。接下来的单分支语句是确保算法中的除法“m/n”时的除数n不为0。注意,如果一开始的n就是O,则两个最大公约数就是m,此处利用返回语句返回的函数值就是m。接下来的do-while循环是实现算法步骤中的第②步和第③步的,显然该循环体中的第2条单分支语句是完成算法步骤中的第③步工作的,而空白处应该完成算法步骤中的第②步工作,即r等于m/n的余数。
【答案】r=m%n;
【说明】求最大公约数和最小公倍数的算法是常用算法;但在教材中并没有给出,希望读者在
学有余力的情况下,能掌握这两个算法。
求两个正整数的最小公倍数的算法在教材中也没有给出,下面给出求最小公倍数的一种算法。设有两个正整数m、n,求它们的最小公倍数的算法如下:
①若m<n,则交换m和n(保证m大于n)。
②令d=m。
③若d能被n整除,则算法结束,d就是m和n的最小公倍数。
否则,令d=d+m,转第③步,继续执行。
实现算法的程序清单如下:
main()
{ int m, n, d ;
scanf("%d,%d",&m,&n);
if(m<n)
{ d=m;m=n;n=d;}
if(n==0)
d=0;
else
{ d=m;
while(d%n!=0)
d+=m;
}
printf(”%d\n”,d);
}
11 阅读下列函数,写出该函数的主要功能。
float f(float s[],int n)
{ int i;
float sum=0.0,*p;
for(p=s;p<s+ n;p++)
sum+=*p;
return(sum);
}
【分析】该函数有2个参数:一个是单精度型一线数组s,一个是整型变量n。函数体中是一个用指针变量控制的次数型循环(循环开始前p指向数组S首地址,即指向下标为0的数组元素;每次循环后p加1,即指向后一个数组元素;退出循环的条件是P指向下标为 n的数组元素),该循环次数为 n,恰好是顺序处理数组 s中的元素 s[0]、s[1」、…、s[n-l」。其实,这个次数型循环是利用指针变量依次处理数组元素的标准程序段。循环体的功能是将当前数组元素加到变量sum中,变量sum在循环前清0,所以这段程序的功能是计算数组s的前n个数组元素之和。函数体的最后一条语句是返回语句,返回值就是求出的数组元素之和(sum值)。
【答案】求数组a中前n个数据的总和,该函数的返回值就是求出的前n个元素和。
12 阅读下列函数,写出该函数的主要功能。
void f(int s「3」[5],int flag)
{ int i, j,*p= s ;
switch(flag)
{case 1:for(i=0;i<3;i++)
{ printf(”\n“
for(j=0;j<5;j++)
printf("%6d",*(p+i*5+j));
}
break ;
case 2:for(i=0;i<5;i++)
{ printf(”\n”);
for(j=0;j<3;j++)
printf("%6d",*(p+j*5+i));
}
}
return;
}
【分析】函数体中有两条语句,前一条语句是多分支语句(switch语句),后一条语句是无返回值的返回语句,显然,函数功能主要取决于前一条switch语句。
switch语句中有两个分支:前一个分支的条件是形式参数 flag的位等于 1;后一个分支 的条件是形式参数flag的值等于2。
先分析前一个分支的功能。该分支是一个二重循环结构,外层循环3次,其循环体有两条语句,第1条是输出一个回车换行符,第2条是次数为5的次数型循环(即内层循环)。内层循环体是一条输出语句:输出的值为“*(p+i*5+j)”,由于指针变量p是指向二维数组a的首地址的,所以这个表达式的值就是a「i」「j」的值。不难看出,这个分支是按照3行5列的格式输出3行5列的二维数组s的元素值。
再分析后一个分支的功能。请注意,这个分支和第1个分支的功能非常类似,唯一不同的是外层循环执行5次,内层循环执行3次。内层循环体中输出语句输出的值为“*(p+j*5+i)”,显然这个表达式的值就是a[j][i]的值。不难看出,这个分支是按照5行3列的格式输出3行5列的二维数组s(转置后的)的元素值。
【答案】该函数无返回值。
如果形式参数flag值为1,按横对应行、纵对应列的格式输出二维数组元素;
如果形式参数flag值为2,按横对应列、纵对应行的格式输出二维数组元素;
如果形式参数flag值不为1或者2,则不输出二维数组元素。
13 阅读下列程序,写出程序运行的输出结果。
char *f(pl,p2)
char *pl,*p2;
{ char*pp1=p1,*pp2=p2,ch;
while(*pp1!='\0')
{ for(ch='0';ch<*pp1;ch++)
*pp2=*(pp1+1),pp2++;
ppl=ppl+2;
}
*pp2='\0';
return(p2);
}
main()
{ char sl[10]={"la2b3c"},s2[20],*p;
p=f(sl,s2);
printf(” % s \n”, p);
}
【分析】首先分析主函数。字符型数组s1中存放一个字符串,调用函数f()后,返回值存入指针型变量p中,再输出p指向的字符串,所以该程序的输出结果就是函数f()返回值所指向的字符串。
再分析函数f()的功能及其返回值。先对函数进行一般的测览,就可以看出该函数的返回值就是形式参数 p2指向的字符串首地址。关键是要搞清楚形式参数 p2指向的字符串等于什么?我们可以用记录的方式记录p2指向的字符串。记录结果如下:
从主函数调用语句(形参和实参结合)和函数体的数据定义语句中可以看出:
指针变量ppl和pl指向数组s1中存放的字符串、指针变量pp2和p2指向数组s2首地址。
执行 while循环:
*ppl等于字符'1'条件(*pp1='\0')满足,执行while循环体;
执行 for循环,ch值为'0',条件ch<*ppl(*ppl是‘1')成立,执行 for循环体;
将*(ppl+1)(值是'a'),存入 pp2指向的数组元素 s2[0] 、pp2++,指向s[1]
ch++,ch值为'l',条件ch<*ppl(*ppl是'l')不成立,退出for循环体;
执行ppl加 2,ppl指向数组 sl的元素 sl「2」,其值为'2',继续 while循环;
*ppl等于字符'2',条件(勺p1!=' \0'顺足,执行 while循环体;
执行 for循环, oh值为'0',条件 ch<*pp1(*pp1是'2')成立,执行 for循环体;
将*(ppl+1)(值是‘b'),存入pp2指向的数组元素s2[l」、pp2++,指向 s2[2]
ch++, ch值为‘1',条件 ch<*pp1(*ppl是'2')成立,执行for循环体;
将*(ppl+l)(值是'b'),存入pp2指向的数组元素s2[2」、pp2++,指向s2[3]
ch++,ch值为'2',条件ch<*ppl(*ppl是'2')不成立,退出for循环体;
执行ppl加2,ppl指向数组s1的元素s1「4」,其值为'3',继续while循环;
*pp1等于字符'3',条件(*pp1!='\0')满足,执行while循环体;
执行 for循环,ch值为'0',条件ch<*pp1(*pp1是'3')成立,执行 for循环体;
将*(pp1+1)(值是'c'),存入pp2指向的数组元素a[3」、 pp2++,指向a2[4]
ch++,ch值为'1'条件ch<*pp1(*pp1是'3')成立,执行for循环体;
将*(pp1+1)(值是'c'),存入 pp2指向的数组元素a[4」、 pp2++,指向a[5」
ch++,ch值为'2',条件ch<*pp1(*pp1是'3')成立,执行for循环体;
将*(pp1+1)(值是'c'),存入pp2指向的数组元素s2[5」、pp2++,指向s2[6」
ch++,ch值为'3',条件ch<*pp1(*pp1是'3')不成立,退出for循环体;
执行pp1加2,pp1指向数组s1的元素s1[6」,其值为'\0',继续while循环;
*pp1等于字符'\0',条件(*pp1='\0')不满足,退出while循环。
执行*pp2='\0',即将字符串结束标记存入pp2指向的数组元素s2「6」;
最后执行返回语句,返回值是形式参数p2,该值等于字符型数组s2的首地址。
现在可以进行总结了,该程序输出的是字符型数组s2中存放的字符串,而该字符串就是:"abbccc"。
【答案】abbccc
14 编一个函数,计算并返回三角形的面积。其中三角形的三个边长作为函数的参数。
(提示:三角形面积s的计算公式如下:sqrt(l(l-a)(l-b)(l-c)),其中:l=(a+b+c)/2)
【分析】函数的形式参数规定为三角形的三个边长(形式参数名称可以选取a、b、c),在函数体中计算三角形的面积,并存入函数体中定义的局部变量s中,最后利用返回语句返回s中的面积。
【答案】 # include"math.h"
float f(a, b,c)
float a,b,c;
{ float l,s;
l=(a+b+c)/2.0;
s=sqrt(l*(l-a)*(l-b)*(l-c));
return(s);
}
15 编一个函数,在一个字符串中查找某个字符,查到则返回“1”;查不到则返回“0”。其中字符申和待查字符均作为函数的参数,要求形式参数使用指针方式。
【分析】在字符串中查找某个字符有标准算法,实现的方法是一个当型循环结构。控制循环的条件是当前字符不是字符串结束标记则继续循环。在循环体中依次处理当前字符,和待查字符比较,相等则在标记变量中设置查到的标记,强迫退出循环;查不到,则继续循环。退出循环以后,根据标记变量的值确定是否查到。
【答案】int my_found(s,ch)
char *s,*ch;
{ int flag=0;
char *p=s;
while(*p!='\0')
{ if(*p==*ch)
{ flag=1;
break;
}
p++;
}
return(flag);
}
16 编一个能递归调用的函数,按照下列公式计算并返回y(n)的值。n作为函数的参数。
y=1 n=1
y=2 n=2
y(n)=y(n一1)*y(n-2) n>2
【分析】按照教材中(或者前面“知识点”中第 3点)介绍的递归函数设计方法,参照给出的递归公式,很容易设计出该递归函数。
【答案】 long y(n)
int n;
{ if(n==1) return(1);
else if(n==2)return(2);
else return(y(n- 1)* y(n-2));
}