今天呢,我们来一起复习函数部分,其实我感觉啊,函数是最简单的部分了,只要你前面有好好学,函数就是一小块一小块的,和写普通代码没什么两样,就是x^2+6-y 与f(x)的关系啦,如果多次使用到一个长长和函数表达式,这时就不妨用f(x)代替啦。
先举个例子:
#include <stdio.h>
int main()
{ void print_star(); //声明print_star函数
void print_message(); //声明print_message函数
print_star(); //调用print_star函数
print_message(); //print_message函数
print_star(); //调用print_star函数
return 0;
}
void print_star() //定义print_star函数
{ printf("*******----*******\n"); //输出一行*号
}
void print_message() //定义print_message函数
{ printf("Good morning!\n"); //输出一行文字信息
}
看到这个你可能会说,啊啊啊小编你个笨蛋,还不如我直接写的简单呢,用函数干嘛呢。但是,你想想,如果给你100个名字,让你给每人说一句早安,你还要一个一个打一遍吗,这就是一个简单的例子。
(1) 指定函数的名字,以便以后按名调用。
(2) 指定函数的类型,即函数返回值的类型。
(3) 指定函数的参数的名字和类型,以便在调用函数时向它们传递数据。对无参函数不需要这项。
(4) 指定函数应当完成什么操作,也就是函数是做什么的,即函数的功能。这是最重要的,是在函数体中解决的。
1.定义无参函数
类型名 函数名(void)
{
函数体
}
2.定义有参函数
类型名 函数名(形式参数表列)
{
函数体
}
3.定义空函数
类型名 函数名()
{ }
//函数体为空,什么也不做。
第三个形式我们都很少见到,我也不知道做不做要求,但前两个必须熟记。
函数调用的形式为:
函数名(实参表列)
如
print_star(); //调用无参函数
c=max(a,b); //调用有参函数
调用函数有以下三点:
1.函数调用语句
把函数调用单独作为一个语句。如printf_star();
这时不要求函数带回值,只要求函数完成一定的操作。
2. 函数表达式
函数调用出现在另一个表达式中,如c=max(a,b);
这时要求函数带回一个确定的值以参加表达式的运算。
3. 函数参数
函数调用作为另一个函数调用时的实参。如m=max(a,max(b,c));,又如:printf (″%d″, max (a,b));
例:输入两个整数,要求输出其中值较大者。要求用函数来找到大数。
#include <stdio.h>
int main()
{ int max(int x,int y); //对max函数的声明
int a,b,c;
printf("please enter two integer numbers:"); //提示输入数据
scanf("%d,%d",&a,&b); //输入两个整数
c=max(a,b); //调用max函数,有两个实参。大数赋给变量c
printf("max is %d\n",c); //输出大数c
return 0;
}
int max(int x,int y) //定义max函数,有两个参数
{
int z; //定义临时变量z
z=x>y?x:y; //把x和y中大者赋给z
return(z); //把z作为max函数的值带回main函数
}
解析:
定义函数,名为max,函数类型为int。指定两个形参x和y,形参的类型为int。
主函数中包含了一个函数调用max(a,b)。max后面括号内的a和b是实参。a和b是在main函数中定义的变量,x和y是函数max的形式参数。通过函数调用,在两个函数之间发生数据传递,实参a和b的值传递给形参x和y,在max函数中把x和y中的大者赋给变量z,z的值作为函数值返回main函数,赋给变量c。
实参可以是常量,变量或表达式。
1.在定义函数中制定的形参,在没有出现函数调用时,它们不占内存中的存储单元。在发生函数调用时,函数的形参被临时分配内存单元。
2.将实参的值传递给形参。
3.在执行函数时,由于形参已经有值,可以用形参进行计算。
4.通过return语句将函数值带回到主函数,如果函数不需要返回值,则不需要return语句。
5.调用结束后,形参被释放掉。实参仍保留原值,不发生改变。
注意:实参向形参的数据传递是“值传递”,单向传递,只能由实参传给形参,不能由形参传给实参。
C语言中函数实参传递给形参,实参与形参是从右向左结合;
在调用函数过程中发生的实参与形参间的数据传递称为“虚实结合”。
通常,希望通过函数调用使主调函数能得到一个确定的值,这就是函数值(函数的返回值)
(1) 函数的返回值是通过函数中的return语句获得的。一个函数中可以有一个以上的return语句,执行到哪一个return语句,哪一个return语句就起作用。return语句后面的括号可以不要,如“return z;”与“return(z);”等价。return后面的值可以是一个表达式。
(2) 函数值的类型。函数值的类型在定义函数时指定。
(3) 在定义函数时指定的函数类型一般应该和return语句中的表达式类型一致。
如果函数值的类型和return语句中表达式的值不一致,则以函数类型为准。对数值型数据,可以自动进行类型转换。即函数类型决定返回值的类型。
(4) 对于不带回值的函数,应当用定义函数为“void类型”(或称“空类型”)。这样,系统就保证不使函数带回任何值,即禁止在调用函数中使用被调用函数的返回值。此时在函数体中不得出现return语句。
int max (float x,float y) //函数值为整型
char letter (char c1,char c2) //函数值为字符型
double min (int x,int y) //函数值为双精度型
例:输入两个实数,用一个函数求出它们之和。
#include <stdio.h>
int main()
{ float add(float x, float y); //对add函数作声明
float a,b,c;
printf("Please enter a and b:"); //提示输入
scanf("%f%f",&a,&b); //输入两个实数
c=add(a,b); //调用add函数
printf("sum is %f\n",c); //输出两数之和
return 0;
}
float add(float x,float y) //定义add函数
{ float z;
z=x+y;
return(z); //把变量z的值作为函数值返回
}
解析:
函数的声明和函数定义中的第1行(函数首部)基本上是相同的,只差一个分号(函数声明比函数定义中的首行多一个分号)。
函数的首行(即函数首部)称为函数原型(function prototype)。
因为在函数的首部包含了检查调用函数是否合法的基本信息(它包括了函数名、函数值类型、参数个数、参数类型和参数顺序),因此,在函数调用时检查函数原型是否与函数声明一致。这样就能保证函数的正确调用。
例:输入4个整数,找出其中最大的数。用函数的嵌套调用来处理。
#include <stdio.h>
int main()
{ int max4(int a,int b,int c,int d); //对max4的函数声明
int a,b,c,d,max;
printf("Please enter 4 interger numbers:"); //提示输入4个数
scanf("%d %d %d %d",&a,&b,&c,&d); //输入4个数
max=max4(a,b,c,d); //调用max4函数,得到4个数中的最大者
printf("max=%d \n",max); //输出4个数中的最大者
return 0;
}
int max4(int a,int b,int c,int d) //定义max4函数
{ int max2(int a,int b); //对max2的函数声明
int m;
m=max2(a,b); //调用max2函数,得到a和b中的大者,放在m中
m=max2(m,c);//调用max2函数,得到a,b,c中的大者,放在m中
m=max2(m,d);//调用max2函数,得到a,b,c,d中的大者,放在m中
return(m); //把m作为函数值带回main函数
}
int max2(int a,int b) //定义max2函数
{ if(a>=b)
return a; //若a≥b,将a作为函数返回值
else
return b; //若a
}
解析:
在主函数中要调用max4函数,因此在主函数的开头要对max4函数作声明。在max4函数中3次调用max2函数,因此在max4函数的开头要对max2函数作声明。由于在主函数中没有直接调用max2函数,因此在主函数中不必对max2函数作声明,只须在max4函数中作声明即可。
max4函数执行过程: 第1次调用max2函数得到的函数值是a和b中的大者,把它赋给变量m,第2次调用max2得到m和c中的大者,也就是a,b,c中的最大者,再把它赋给变量m。第3次调用max2得到m和d中的大者,也就是a,b,c,d中的最大者,再把它赋给变量m。这是一种递推方法,先求出2个数的大者;再以此为基础求出3个数的大者;再以此为基础求出4个数的大者。m的值一次一次地变化,直到实现最终要求。
(1) 可以将max2函数的函数体改为只用一个return语句,返回一个条件表达式的值:
int max2(int a,int b) //定义max2函数
{return(a>=b?a:b);} //返回条件表达式的值,即a和b中的大者
(2) 在max4函数中,3个调用max2的语句可以用以下一行代替:
m=max2(max2(max2(a,b),c),d); //把函数调用作为函数参数
甚至可以取消变量m,max4函数可写成
int max4(int a,int b,int c,int d)
{ int max2(int a,int b); //对max2的函数声明
return max2(max2(max2(a,b),c),d);
}
先调用“max2(a,b)”,得到a和b中的大者。再调用“max2(max2(a,b),c)”(其中max2(a,b)为已知),得到a,b,c三者中的大者。最后由“max2(max2(max2(a,b),c),d)”求得a,b,c,d四者中的大者。
所谓递归调用,就是:在调用一个函数的过程中又出现直接或间接地调用该函数本身,称为函数的递归调用。
int f(int x)
{
int y,z;
z=f(y); //在执行f函数的过程中又要调用f函数
return (2*z);
}
程序中不应出现无终止的递归调用,而只应出现有限次数的、有终止的递归调用,这可以用if语句来控制,只有在某一条件成立时才继续执行递归调用;否则就不再继续。
例:有5个学生坐在一起,问第5个学生多少岁,他说比第4个学生大2岁。问第4个学生岁数,他说比第3个学生大2岁。问第3个学生,又说比第2个学生大2岁。问第2个学生,说比第1个学生大2岁。最后问第1个学生,他说是10岁。请问第5个学生多大。
#include <stdio.h>
int main()
{ int age(int n); //对age函数的声明
printf("NO.5,age:%d\n",age(5)); //输出第5个学生的年龄
return 0;
}
//注意分析递归的终止条件。
int age(int n) //定义递归函数
{ int c; //c用作存放函数的返回值的变量
if(n==1) //如果n等于1
c=10; //年龄为10
else //如果n不等于1
c=age(n-1)+2; //年龄是前一个学生的年龄加2(如第4个学生年龄是第3个学生年龄加2)
return(c); //返回年龄
}
#include <stdio.h>
int main()
{ int fac(int n); //fac函数声明
int n;
int y;
printf("input an integer number:");
scanf("%d",&n); //输入要求阶乘的数
y=fac(n);
printf("%d!=%d\n",n,y);
return 0;
}
//注意分析递归的终止条件
int fac(int n) //定义fac函数
{
int f;
if(n<0) //n不能小于0
printf("n<0,data error!");
else if(n==0||n==1) //n=0或,1时n!=1
f=1; //递归终止条件
else
f=fac(n-1)*n; //n>1时,n!=n*(n-1)
return(f);
}
注意:
程序中的变量是int型,如果用Visual C++、GCC以及多数C编译系统为int型数据分配4个字节,能表示的最大数为2 147 483 647,当n=12时,运行正常,输出为479 001 600。如果输入13,企图求13!,是得不到预期结果的,因为求出的结果超过了int型数据的最大值。可将f,y和fac函数定义为float或double型。
例:有两个班级,分别有35和30名学生,调用average函数,分别求这两个班的学生的平均成绩。
#include <stdio.h>
int main()
{ float average(float array[],int n);
float score1[5]={98.5,97,91.5,60,55}; //定义长度为5的数组
float score2[10]={67.5,89.5,99,69.5,77,89.5,76.5,54,60,99.5};
//定义长度为10的数组
printf("The average of class A is %6.2f\n",average(score1,5));
//用数组名score1和5作实参
printf("The average of class B is %6.2f\n",average(score2,10));
//用数组名score2和10作实参
return 0;
}
float average(float array[],int n) //定义average函数,未指定形参数组长度
{ int i;
float aver,sum=array[0];
for(i=1;i<n;i++)
sum=sum+array[i]; //累加n个学生成绩
aver=sum/n;
return(aver);
}
注意:
用数组名作函数实参时,不是把数组元素的值传递给形参,而是把实参数组的首元素的地址传递给形参数组,这样两个数组就共占同一段内存单元。
例:有一个3×4的矩阵,求所有元素中的最大值。
#include <stdio.h>
int main()
{ int max_value(int array[][4]); //函数声明
int a[3][4]={{1,3,5,7},{2,4,6,8},{15,17,34,12}}; //对数组元素赋初值
printf("Max value is %d\n",max_value(a));
//max_value(a)为函数调用
return 0;
}
int max_value(int array[][4]) //函数定义
{ int i,j,max;
max=array[0][0];
for(i=0;i<3;i++)
for(j=0;j<4;j++)
if(array[i][j]>max) max=array[i][j]; //把大者放在max中
return(max);
}
解析:
形参数组array第1维的大小省略,第2维大小不能省略,而且要和实参数组a的第2维的大小相同。在主函数调用max_value函数时,把实参二维数组a的第1行的起始地址传递给形参数组array,因此array数组第1行的起始地址与a数组的第1行的起始地址相同。由于两个数组的列数相同,因此array数组第2行的起始地址与a数组的第2行的起始地址相同。a[i][j]与array[i][j]同占一个存储单元,它们具有同一个值。实际上,array[i][j]就是a[i][j],在函数中对array[i][j]的操作就是对a[i][j]的操作。
ok函数的复习到这里就结束了,明天是最后一天了喔,哈哈哈,终于要去复习完了,坚持就是胜利呀。
明天我们复习第五章 结构体&指针