函数的定义和调用
例7.1 想输出以下的结果,用函数调用实现。
程序设计如下:
#include <stdio.h>
int main()
{
void print_star();//对print_star函数进行声明
void print_message();//对print_message函数进行声明
print_star();//调用函数
print_message();
print_star();
return 0;
}
void print_star()
{
printf("*******************\n");
}
void print_message()
{
printf(" How do you do!\n");
}
运行程序如下:
定义函数应包括以下几个内容:
(1)指定函数的名字,以便以后按名调用。
(2)指定函数的类型,即函数值的类型。
(3)指定函数的参数的名字和类型,以便在调用函数时向它们传递数据。对无参函数不需要这项。
(4)指定函数应当完成什么操作,也就是函数是做什么的,即函数的功能。这是最重要的,这是在函数体中解决的。
例7.2 输人两个整数,求输出二者中的大者。要求在主函数中输人两个整数,用一个函数max求出其中的大者,并在主函数中输出此值。
程序设计如下:
#include <stdio.h>
int main()
{
int max(int x,int y);
int a,b,c;
printf("please input two number:");
scanf("%d,%d",&a,&b);
c=max(a,b);
printf("max is %d\n",c);
return 0;
}
int max(int x,int y)
{
int z;
if(x>y) z=x;
else z=y;
return z;
}
运行程序如下:
函数的嵌套调用
例7.3输入4个整数,找出其中最大的数。用一个函数来实现。
程序设计如下:
#include <stdio.h>
int main()
{
int max_4(int a,int b,int c,int d);//对max_4函数的声明
int a,b,c,d,max;
printf("please enter 4 integer numbers:");
scanf("%d %d %d %d",&a,&b,&c,&d);
max=max_4(a,b,c,d);//调用max_4函数,得到4个数中的最大者,赋给变量max
printf("max=%d \n",max);
return 0;
}
int max_4(int a,int b,int c,int d)//定义max_4函数
{
int max(int,int);//max函数的声明
int m;
m=max(a,b);//调用max函数
m=max(m,c);
m=max(m,d);
return m;
}
int max(int x,int y)
{
if(x>y)
return x;
else
return y;
}
运行程序如下:
函数的递归调用
例7.4 有5个学生坐在一起,问第5个学生多少岁?他说比第4个学生大2岁。问第4个学生岁数,他说比第3个学生大2岁。问第3个学生,又说比第2个学生大2岁。问第2个学生,说比第1个学生大2岁。最后问第1个学生,他说是10岁。请问第5个学生多大。
程序设计如下:
可以用一个age函数来描述上述递归过程:
int age(int n)//求年龄的递归函数
{
int c;//变量c用作存放函数的返回值的变量
if(n==1)
c=10;
else
c=age(n-1)+2;//在执行age函数过程中又调用age函数,即递归调用
return c;
}
用一个主函数调用age函数,求得第5个学生的年龄:
#include <stdio.h>
int main()
{
printf("%d\n",age(5));//输出第5个学生的年龄
return 0;
}
运行程序如下:
注意:在调用一个函数过程中调用另一个函数,称为函数的嵌套调用
在调用一个函数过程中直接或间接调用本函数,称为函数的递归调用
例7.5 分别用递推方法和递归方法求n!,即1X2X3X…Xn。
1.用递推方法求n!
递推法的特点是从一个已知的事实出发,按一定规律推出下一个事实,再从这个新的已知的事实出发,再向下推出一个新的事实……。
程序设计如下:
#include <stdio.h>
int main()
{
long fac(int n);//对fac函数进行声明
int n;
long fact=0;//变量fact用来存放n!的值
printf("please input a integer number:");
scanf("%d",&n);
fact=fac(n);//调用fac函数,求出n!
printf("%d!=%ld\n",n,fact);//输出n!
return 0;
}
long fac(int n)
{
int i;
long fac=1;
for(i=1;i<=n;i++)
fac=fac*i;
return fac;
}
运行程序如下:
2.用递归方法求n!
程序设计如下:
#include <stdio.h>
int main()
{
long fac(int n);//对fac函数的声明
int n,y;
printf("input an integer number:");
scanf("%d",&n);
y=fac(n);//调用fac函数
printf("%d!=%ld\n",n,y);
return 0;
}
long fac(int n)//定义fac函数
{
long f;
if(n<0)
printf("n<0,data error!");//若输入的n<0,输出不合法
else if(n==0,n==1)
f=1;//0!和1!等于1
else f=fac(n-1)*n;//递归调用fac函数
return f;//f就是n!
}
运行程序如下:
注意:一个问题能否用递归方法处理,取决于以下3个条件:
(1)所求解的问题能转化为用同一方法解决的子问题,例如求n!可以转化为(n1)!Xn。(n-1)!就是子问题,它的求解方法与n!是相同的。
(2)子问题的规模比原问题的规模小,如求(n-1)!比求n!的规模小,规模应是有规律地递减,表现在调用函数时,参数是递减的。如第一次调用fac(5),第二次调用fac(4)……
(3)必须要有递归结束条件(边界条件),例如fac(1)=1和fac(0)=1。停止递归,否则形成无穷递归,系统无法实现。
数组作为函数
例7.6 有两个运动队a和b,各有10个队员,每个队员有一个综合成绩。将两个队的每个队员的成绩按顺序一一对应地逐个比较(即a队第1个队员与b队第1个队员比,….)。如果a队队员的成绩高于b队相应队员成绩的数目多于b队队员成绩高于a队相应队员成绩的数目(例如,a队赢6次,b队赢4次),则认为a队胜。统计出两队队员比较的结果(a队高于、等于和低于b队的次数)
程序设计如下:
#include <stdio.h>
int main()
{
int higher(int x,int y);//对higher函数的声明
int a[10],b[10],i,n=0,m=0,k=0;
printf("enter array a:\n");
for(i=0;i<10;i++)
scanf("%d",&a[i]);
printf("\n");
printf("enter array b:\n");
for(i=0;i<10;i++)
scanf("%d",&b[i]);
printf("\n");
for(i=0;i<10;i++)
{
if(higher(a[i],b[i])==1)//如a队队员成绩高于b队相应队员
n++;
else
if(higher(a[i],b[i])==0)//如a队队员成绩等于b队相应队员
m++;
else//如a队队员成绩低于b队相应队员
k=k+1;
}
printf("a higher b %d times\na equal to b %d times\nb higher a %d times\n",n,m,k);
if(n>k)
printf("a wins!\n");
else if(n<k)
printf("b wins!\n");
else
printf("a is equal to b\n");
return 0;
}
higher(int x,int y)//定义 higher 函数
{
int flag;
if(x>y) flag=1;//x队队员成绩高于y队相应队员,使flag等于1
else if(x<y) flag=-1;//如y队队员成绩高于x队相应队员,使flag等于-1
else flag=0;//如x队队员成绩等于y队相应队员,使flag等于0
return flag;//将1或-1,0返回主函数
}
运行程序如下:
例7.7 有10个学生成绩,用一个函数求全体学生的平均成绩。
程序设计如下:
#include <stdio.h>
int main()
{
float average(float array[10]);//函数声明
float score[10],aver;
int i;
printf("input 10 scores:\n");
for(i=0;i<10;i++)
scanf("%f",&score[i]);
aver=average(score);//以数组名为实参调用average函数
printf("average score is %5.2f\n",aver);
return 0;
}
float average(float array[10])//定义求平均成绩的函数average
{
int i;
float aver,sum=array[0];
for(i=1;i<10;i++)
sum=sum+array[i];
aver=sum/10;
return aver;
}
运行程序如下:
例7.8 有两个班,学生数不同,编写一个函数,用来分别求各班的平均成绩。
程序设计如下:
#include <stdio.h>
int main()
{
float average(float array[],int n);//对 average函数的声明
float score_1[5]={98.5,97,91.5,60,55};
float score_2[10]={67.5,89.5,99,69.5,77,89.5,76.5,54,60,99.5};
printf("The average of class A is %6.2f\n",average(score_1,5));
printf("The average of class B is %6.2f\n",average(score_2,10));
return 0;
}
float average(float array[],int n)//没有指定形参数组的大小,形参n用来接收本班人数
{
int i;
float aver,sum=array[0];//sum的初值是第1个学生的成绩
for(i=1;i<n;i++)
sum=sum+array[i];//将array [1]到array [n]界加到sum中
aver=sum/n;
return aver;
}
运行程序如下:
例7.9 用一个函数实现用选择法对10个整数按升序排列。
程序设计如下:
#include <stdio.h>
int main()
{
void sort(int array[],int n);//对sort 函数的声明
int a[10],i;
printf("enter the array:\n");
for(i=0;i<10;i++)//输入a数组10个元素
scanf("%d",&a[i]);
sort(a,10);
printf("The sorted array:\n");
for(i=0;i<10;i++)//输出已排好序的10个数
printf("%d ",a[i]);
printf("\n");
return 0;
}
void sort(int array[],int n)//选择法排序函数
{
int i,j,k,t;
for(i=0;i<n-1;i++)
{
k=i;//k用来存放当前"最小"的元素的序号
for(j=i+1;j<n;j++)//将第i个元素与其后各元素比较
if(array[j]<array[k])
k=j;//把当前最小元素的序号j保存在k中
t=array[k];
array[k]=array[i];
array[i]=t;//将最小元素与array[i]对换
}
}
运行程序如下:
例7.10 有4个学生,5门课的成绩,设计一个函数,用来求出其中的最高成绩。
程序设计如下:
#include <stdio.h>
int main()
{
float highest_score(float array[4][5]);
float score[4][5]={{61,73,85.5,87,90},{72,84,66,88,78},
{75,87,93.5,81,96},{65,85,64,76,71}};
printf("The highest score is %6.2f\n",highest_score(score));
return 0;
}
float highest_score(float array[4][5])
{
int i,j;
float max;
max=array[0][0];
for(i=0;i<4;i++)
for(j=0;j<5;j++)
if(array[i][j]>max) max=array[i][j];
return max;
}
运行程序如下:
参数变量的作用域和生存期
例7.11 有4个学生,5门课的成绩,要求输出其中的最高成绩以及它属于第几个学生、第几门课程。
程序设计如下:
#include <stdio.h>
int Row,Column;//定义全局变量Row和 Column
int main()
{
float highest_score(float array[4][5]);
float score[4][5]={{61,73,85.5,87,90},{72,84,66,88,78},
{75,87,93.5,81,96},{65,85,64,76,71}};
printf("The highest score is %6.2f\n",highest_score(score));
printf("Student No.is %d\nCourse No. is %d\n",Row,Column);
return 0;
}
float highest_score(float array[4][5])
{
int i,j;
float max;
max=array[0][0];
for(i=0;i<4;i++)
for(j=0;j<5;j++)
if(array[i][j]>max)
{
max=array[i][j];
Row=i;//将行的序号赋给全局变量Row
Column=j;//将列的序号赋给全局变量Column
}
return max;
}
运行程序如下:
例7.12 输出1~5的阶乘值。
程序设计如下:
#include <stdio.h>
int main()
{
int fac(int n);
int i;
for(i=1;i<=5;i++)//先后5次调用 fac函数
printf("%d!=%d\n",i,fac(i));//每次计算并输出i!的值
return 0;
}
int fac(int n)
{
static int f=1;//f保留了上次调用结束时的值
f=f*n;//在上次的f值的基础上再乘以n
return f;//返回值f是n!的值
}
运行程序如下:
关于静态局部变量的说明:
①静态局部变量属于静态存储类别,在静态存储区内分配存储单元。在程序整个运行期间都不释放。而自动变量(即动态局部变量)属于动态存储类别,占动态存储区空间而不占静态存储区空间,函数调用结束后即释放。
②对静态局部变量是在编译时赋初值的,即只赋初值一次,在程序运行时它已有初值。以后每次调用函数时不再重新赋初值而只是保留上次函数调用结束时的值。而对自动变量赋初值,不是在编译时进行的,而是在函数调用时进行,每调用一次函数重新给一次初值,相当于执行一次赋值语句。
③如在定义局部变量时不赋初值,则对静态局部变量来说,编译时自动赋初值0(对数值型变量)或空字符(对字符变量)。而对自动变量来说,如果不赋初值则它的值是一个不确定的值。这是由于每次函数调用结束后存储单元已释放,下次调用时又重新另外分配存储单元,而所分配的单元中的值是不可知的。
④虽然静态局部变量在函数调用结束后仍然存在,但其他函数是不能引用它的。因为它是局部变量,只能被本函数引用,而不能被其他函数引用。
⑤用静态存储要多占内存(长期占用不释放,而不能像动态存储那样一个存储单元可供多个变量使用,节约内存),而且降低了程序的可读性,当调用次数多时往往弄不清静态局部变量的当前值是什么。因此不是必要,不要多用静态局部变量。
内部函数和外部函数
例7.13 有一个字符串,内有若干个字符,现输人一个字符,如果字符串中包含此字符,则把它删去。用外部函数实现。
程序设计如下:
#include <stdio.h>
int main()
{//以下3行是对在本函数中将要调用的在其他文件中定义的3个函数进行声明
extern void enter_astring(char str[]);
extern void delete_string(char str[],char ch);
extern void print_string(char srt[]);
char c;//c是准备删除的字符
char str[80];//定义字符数组
enter_string(str);//调用 enter_string函数,输入字符串
scanf("%c",&c);//输人希望删除的字符
delete_string(str,c);//调用delete_string函数,删除字符
print_string(str);//调用 print_string函数,输出已删除字符后的字符串
return 0;
}
#include <stdio.h>
void enter_string (char str [80]) //定义外部函数 enter_string,用来读入字符串
{
gets (str);//向字符数组输人字符串
}
#include <stdio.h>
void delete_string (char str[], char ch) //定义外部函数 delete_string,用来删除字符
{
int i,j;
for(i=j=0; str[i]!='\0';i++)
if(str[i]!=ch)
str[j++]=str[i];
str [j]='\0';
}
#include <stdio.h>
void print_string (char str [])
{
printf("%s\n", str);//定义外部函数 print_string,用来输出字符串
}
运行程序如下:
例7.14 Hanoi(汉诺)塔问题。这是一个古典的数学问题,是一个用递归方法解题的典型例子。古印度有一个梵塔,塔内有3个柱子A、B、C,开始时A柱上套有64个盘子,盘子大小不等,大的在下,小的在上(见图7.17)。有一个老和尚想把这64个盘子从A柱移到C柱,但规定每次只能移动一个盘,且在任何时候3个柱上的盘子都是大盘在下,小盘在上。在移动过程中可以利用B柱。有人说,当移动完这些盘子时,世界末日就到了。
现在利用计算机来模拟移动盘的过程。要求输出移动盘子的每一步。
程序设计如下:
#include <stdio.h>
int main()
{
void hanoi(int n,char x,char y,char z);//对调用的函数hanoi的声明
int m;//m是需要移动的盘子数
printf("input the number of dishes:");
scanf("%d",&m);//输入盘子数
printf("The step to moving %d dishes:\n",m);
hanoi(m,'A','B','C');//执行移动盘子
return 0;
}
void hanoi(int n,char x,char y,char z)//定义hanoi函数
{
void move(char a,char b);//对调用的函数move的声明
if(n==1) move(x,z);//最后一个和尚只需移动一个盘子
else
{
hanoi(n-1,x,z,y);//递归调用下一个和尚移动n-1个盘子
move(x,z);//自己移动一个盘子
hanoi(n-1,y,x,z);//递归调用下一个和尚移动n-1个盘子
}
}
void move(char a,char b)
{
printf("%c-->%c\n",a,b);//移动一个盘子的路径
}
运行程序如下: