第七章 用函数实现模块化程序设计
(1)为什么要用函数?
@function既是函数也是功能。函数就是用来完成一定功能的的(函数就是功能),函数名就是给这个功能起一个名字,一个C程序可由一个主函数和若干个其他函数构成。
所有的函数都是平行的,即在函数定义时是分别进行,是互相独立。
例题://输出以下结果,用过调用函数实现
/*
***********
How are you!
***********
*/
#include<stdio.h>
int main()
{
void print_star(); //声明void print_star()函数
void print_message(); //声明void print_message函数
print_star(); //调用print_star函数
print_message(); //调用print_message函数
print_star(); //用print_star函数
return 0;
}
void print_star() //定义void print_star函数,这里后面不能有";"符号
{
printf("****************
");
}
void print_message() //定义void print_message函数
{
printf("How are you!
"); //输出一行文字信息
}
(2)怎样定义函数
@在程序中若用到数学函数【如:sqrt、fabs、sin cos等】必须在文本开头写上(#include<math.h>)
函数的定义包括以下几个内容
1.指定函数的名字,以便以后按名调用。
2.指定函数类型,即函数值返回类型。
3.指定函数的名字和类型,在调用时向他们传递数据。
4.指定函数应当完成什么操作,也就是函数应该做什么,就是函数的功能。
定义函数的方法:
1.定义无参函数:
一般形式为:
类型名 函数名() 类型名 函数名(void)
{ {
函数体 或 函数体 //包括声明部分和语句部分
} }
函数名后面括号内的void表示“空”即函数没有参数
2.定义有参函数:
一般形式为: 例如:定义max函数
类型名 函数名(形式参数表列) int max(int x,int y);
{ { int z;
函数体 z=x>y?x:y;
return (z);
} }
3.定义空函数(先占用一个位置,后面在编写好的程序放上去)
一般形式为:
类型名 函数名()
{}
例如: void dummy()
{}
【merge():合并 ; matproduct():矩阵相乘 ; concatenate():字符串连接; shell(): 希尔排序】
(3)调用函数
1.一般形式为:
函数名(实参表列)//若是无参函数,则实参表列可以没有,但是括号不能省
例如: print_star(); //调用无参函数
c=max(a,b)//调用有参函数
2. 3种函数调用方式
函数调用语句 、函数表达式、函数参数
3.函数调用时的数据传递
形式参数和实际参数、实参和形参间的数据传递。
4.函数的调用过程
5函数的返回值
它是通过return语句获得
函数值的类型
再定义函数时指定的函数类型一般应该和return语句中的表达式类型一致
**(如果函数值的类型和return语句中表达式的值不一样,以函数类型为准)
(4)对被调用函数的声明和函数原型:
*函数的首行(即函数的首部)成为函数的原型,使用函数原型作声明是C语言的一个重要特点。
*函数的定义是指对函数功能的确立,包括函数名,函数值类型、形参及其类型以及函数体等,他是一个完整的、独立的函数单位。
函数声明有两种:
1.函数类型 函数名(参数类型1 参数名1,参数类型2 参数名2.....);
2.函数类型 函数名(参数类型1,参数类型2,.....);
(5)函数的嵌套使用:
@C语言的函数定义是相互平行的、独立的,也就是说,在定义函数时,一个函数不能再定义另一个函数就是不能嵌套定义,但可以嵌套使用。
例题1://输入4个整数,找出其中最大的数。用函数嵌套调用来处理。
//方法一:
#include<stdio.h>
int main()
{
int max(int r,int x,int y,int z);
int a,b,c,d,e;
printf("请输入4个整数:");
scanf("%d,%d,%d,%d",&a,&b,&c,&d);
e=max(a,b,c,d);
printf("最大的数为:%d
",e);
return 0;
}
int max(int r,int x,int y,int z)
{
int m,n,l;
m=r>x?r:x;
n=m>y?m:y;
l=n>z?n:z;
return (l);
}
//方法二:
/*
#include<stdio.h>
int main()
{
int max4(int a,int b,int c,int d);//对max4函数的声明
int a;
int b;
int c;
int d;
int max;
printf("请输入4个整数:");
scanf("%d,%d,%d,%d",&a,&b,&c,&d);
max=max4(a,b,c,d); //调用max4函数,得到4个数中的最大者
printf("最大的数为:%d
",max);
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=max2(m,d);
return (m);
}
int max2(int a,int b)
{
if(a>=b)
return a;
else
return b;
}
*/
(6)函数的递归调用
在调用一个函数的过程中又出现直接或间接地调用该函数本身,称为函数的递归调用。运用递归调用必须有一个递归结束条件
例如1:直接调用本函数举例
int f(int x)
{
int y,z;
z=f(y);//在执行f函数的过程中又要调用f函数
return (2*z);
}
例题2:/*有五个学生坐在一起,
问第五个学生多少岁,他说比第四个学生大两岁。
问第四个学生岁数,他说比第三个大两岁。
问第三个学生,又说比第二个大两岁。
问第二个学生,他说比第一个大两岁。
最后问第一个学生,他说他十岁。
请问第五个学生多少岁?
*/
//递归过程
/*
int age(int n)
{
int c;
if(n==1)
c=10;
else
c=age(n-1)+2;
return(c);
}
*/
#include <stdio.h>
int main()
{
int age(int n);
printf("NO.5,age:%d
",age(5)); //输出
return 0;
}
int age(int n) //定义递归函数
{
int c;
if(n==1) //n=1时,年龄为10
c=10;
else
c=age(n-1)+2; //n!=1时,年龄是前一个学生的年龄加2
return (c);
}
//递归调用4次,
例题3://利用递归算法求n!
#include<stdio.h>
int main()
{
int fac(int n); //fac 函数声明
int n;
int y;
printf("input integer number:"); //输入要阶乘的数
scanf("%d",&n);
y=fac(n);
printf("%d!=%d
",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;
return (f);
}
(7)数组作为函数参数
调用有参函数,需要提供实参。可以是常量、变量或着表达式。数组元素也可以作为函数实参。
【数据传递方向是从实参到形参,单向传递。】
1.数组元素作为函数实参,不能作为形参。
例题1://输入 10个数,要求输出其中值最大的元素和该数是第几个数。
#include<stdio.h>
int main()
{
int max(int x,int y);
int a[10];
int m;
int n;
int i;
printf("enter 10 integer numbers:");
for(i=0;i<10;i++)
scanf("%d",&a[i]);
printf("
");
for(i=1,m=a[0],n=0;i<10;i++)
{
if(max(m,a[i])>m)
{
m=max(m,a[i]);
n=i;
}
}
printf("The largest number is %d
it is the %dth number.
",m,n+1);
}
int max(int x,int y)
{
return (x>y?x:y);
}
2.数组名作函数参数
【用数组元素做实参时,向形参变量传递是数组元素的值,而用数组名作函数实参时,向形参传递的是数组首元素的地址】
例题2://有一个一维数组score,内放10个学生成绩,求平均成绩
#include<stdio.h>
int main()
{
float average(float array[10]); //函数声明
float score[10];
float aver;
int i;
printf("enter 10 scores:
");
for(i=0;i<10;i++)
scanf("%f",&score[i]);
printf("
");
aver=average(score); //调用average函数
printf("average score is %5.2f
",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);
}
例题3://有两个班级,分别有35名和30名学生,调用一个average函数,分别求这两个班级的学生的平均成绩。
//为了简化,分别设着两个班的人数为5和10
#include<stdio.h>
int main()
{
float average(float array[],int n);
float score1[5]={98.5,97,91,60,55};
float score2[10]={67,88,99,69,77,89,76,54,60,99};
printf("The average of class A is %6.2f
",average(score1,5));
printf("The average of class B is %6.2f
",average(score2,10));//用数组名score1和5做实参
return 0;
}
float average(float array[],int n)
{
int i;
float aver,sum=array[0];
for(i=1;i<n;i++)
sum=sum+array[i];
aver=sum/n;
return(aver);
}
3.多维数组名做函数参数
在被调用函数中对形参数组定义时可以制定每一维大小,也可以省略第一维的大小说明
例题://有一个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
",max_value(a));// max_value(a)为函数调用
return 0;
}
int max_value(int array[][4]) //函数定义
{
int i;
int j;
int 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];
return (max);
}
(8)局部变量和全局变量
从变量的作用域来(从空间)看可分为全局变量和局部变量。
局部变量:在复合语句内定义的,复和语句不能在外面用的就是局部变量。形式参数也是局部变量。
全局变量:在函数之外定义的外部变量是全局变量。
(9)变量的存储方式和生存期
变量的存储方式分为两类:
1.动态存储方式:是在程序运行期间需要进行动态的分配存储空间的方式【形式参数、自动变量、现场保护和返回地址】
2.静态存储方式:在程序运行期间有系统分配固定的存储空间的方式。【全局变量全部放在这里】
3.存储空间又分为三类:程序区、静态存储区和动态存储区【存放数据】。
*变量的存在时间称之为生存期。
*【每一个C语言都包含的属性有:数据的类型、数据存储类别。】
1.存储类别指的是数据在内存中存储的方式(如静态存储方式和动态存储方式)
2.c的存储类别分为四种:自动的auto 、静态的static、寄存器的 register、外部的 extern
局部变量的存储类别(auto static)
1.在调用该函数时,系统会给这些变量分配存储空间,在函数调用结束时会自动释放这些存储空间,这就是自动变量。auto可以隐藏不写;它存储在动态存储区中
2.局部变量的值在函数调用结束后不消失而继续保留原值,及其占用的存储单元不释放,就是静态存储变量。
3.将局部变量的值存储在CPU的寄存器中,需要用时直接从寄存器中取出参加运算