文章目录
- 函数的基础知识
-
- 函数
- 函数的说明
- 函数的使用
- 函数之间的参数传递
-
- 复制传递方式
- 地址传递方式
- 全局变量
- 函数与数组
-
- 复制传递方式
- 地址传递方式
- 指针函数
- 函数指针
-
- 函数指针数组
- 递归函数
函数的基础知识
函数
函数是一个完成特定功能的代码模块,其程序代码独立,通常要求有返回值,也可以是空值。
一般形式如下:
<数据类型> <函数名称>( <形式参数说明> )
{语句序列;return[(<表达式>)];
}
其中:
-
<函数名称>是一个标识符,要求符合标识符的命名规则;
-
<数据类型>是整个函数的返回值类型,如无返回值应该写为void型;
-
<形式参数说明>是逗号”,”分隔的多个变量的说明形式,通常简称为形参;
-
大括弧对 {<语句序列> },称为函数体;
-
<语句序列>是大于等于零个语句构成的。
注意:在函数体中,表达式语句里使用的变量必须事先已有说明,否则不能使用。 -
return[(<表达式>)]语句中表达式的值,要和函数的<数据类型>保持一致;如函数的<数据类型>为void可以省略或者无表达式结果返回(即写成return ;)。
例:定义求xn值的函数( x是实数, n为正整数)。double Power(double x, int n) { if( n<0 ) { printf(“error\n”); return(-111); //如果是负整数,返回-111作为出错的状态值 }int i;double r=1; //定义一个double型变量用以存放结果,并初始化为1for( i=1; i<=n; i++)r *= x;return( r ) ; //要求返回double型结果值为r}int main(void){double a,b;int c;while (scanf("%lf%d",&a,&c)==2){b=Power(a,c);printf("%lf\n",b);}printf("Bye\n");return 0;}
函数的说明
函数的说明就是指函数原型
其中,<形式参数说明>可以缺省说明的变量名称,但类型不能缺省。
例如,
double Power(double x, int n) ;
double Power(double, int);
函数的使用
函数的使用也叫函数的调用,形式如下:
函数名称(〈实际参数〉)
其中:
<函数名称>是一个标识符,符合标识符的命名规则;
〈实际参数〉需要确切的数据,也可以是具有确定值的表达式。实参就是在使用函数时,调用函数传递给被调用函数的数据,用以完成所要求的任务。
注意:
函数调用可以作为一个运算量出现在表达式中,也可以单独形成一个语句。对于无返回值的函数来讲,只能形成一个函数调用语句。
编写一个函数显示 “Hello, guy! ”,然后编写
主程序main调用它。
#include <stdio.h>
void DisplayHello(void)
{ printf(“Hello,guy!\n”);
}
int main(void)
{DisplayHello() ; //一个函数调用语句
}运行结果:Hello, guy! ↙
函数之间的参数传递
复制传递方式
复制传递方式是函数间传递数据常用的式。调用函数将实参传递给被调用函数,被调用函数将创建同类型的形参并用实参初始化。即把实参赋给一个新的变量,把实参复制到新建形参的存储区域中。采用复制传递方式传递数据,被调用函数不能访问调用函数里的实参。被调用函数处理的数据是复制到其形参的数据,因此,即使改变形参的值也不会影响实参的值,一旦被调用函数完成了其任务时,这些形参通常就释放其占用空间 。
复制传递方式的示意图:
上图中,虚箭头线是指将实参的数据拷贝给了形参变量,实参和形参是具有相同数据类型但存储空间是不同的两组空间。被调用函数处理的数据是复制到本地的数据,它不能改变调用函数中实参的数值 。
地址传递方式
地址传递方式和复制传递方式正好相反,这种方式是将调用函数的参数本身传给被调用函数。因此,被调用函数中对形参的操作,将直接改变实参的值。调用函数将实参的地址传送给被调用函数,被调用函数对该地址的目标操作,相当于对实参本身的操作。按地址传递,实参为变量的地址,而形参为同类型的指针。
采用地址传递方式的数据交换例子。
#include <stdio.h>
void Swap(double *x, double *y) ; // Swap函数声明
int main(void)
{double x1, x2;x1=21.56;x2=65.12;Swap(&x1, &x2);//调用Swap函数,交换x1和x2的值printf(“x1=%.2f,x2=%.2f\n”,x1,x2);
}
void Swap(double *x, double *y) //实现x和y指向的目标
{double temp;temp= *x; *x = *y; *y=temp;
}
运行结果:
x1=65.12 x2=21.56↙
全局变量
全局变量就是在函数体外说明的变量,它们在程序中的每个函数里都是可见的。实际上,全局变量也是一种静态型的变量。将它初始化为0。全局变量一经定义后就会在程序的任何地方可见。使用全局变量传递数据的先后顺序的不同会影响计算结果,应用顺序不当,会导致错误,这种方式尽量少用。
全局变量实现函数之间数据通信的例子。
#include <stdio.h>
int n ; //定义一个全局变量n;
double factorial (void) ; // 说明了一个double型的函数factorial
int main(void)
{double s=0; n=10 ; s = factorial( );printf(“%e\n”,s); //调用factorial函数;
}
double factorial (void) //factorial函数功能为计算n! ;
{double r = 1;int i;for(i=1; i<=n; i++) { r *= i; }return( r ) ;
}运行结果:10!=3.6288e+06↙
函数与数组
前面介绍了函数之间的参数传递都是基本数据类型的数据,本节将介绍数组在函数与函数间的传递。与上一节介绍的一样, 数组作为参数在函数间的传递也有复制传递方式、地址传递方式和全局数组传递方式。
复制传递方式
函数与函数之间的数组传递,复制传递方式只是提供一种形式,被调用函数的形参数组的数组名实际上是一个指针变量,因此,复制传递方式与数组的指针传递方式完全相同,只是形参的说明形式不同而已。调用函数将实参数组传递给被调用函数形参,形参接收是实参的地址。由于复制传递方式与下节介绍的指针传递方式一样,被调用函数里对形参数组的操作会影响调用函数里的实参数组。形参数组的说明形式好像是实参的备份,其实不然。
数组复制传递的例子。
#include <stdio.h>
double TestArray(double b[],int Size);
int main(void)
{int i;double a[5]={1.1, 2.1, 3.1, 4.1, 5.1}, r=0;r= TestArray(a,5); printf(“%f\n”,r); //输出rr=0; //在主函数中求出a数组的元素之和for(i=0; i<5; i++) { r += a[i]; }printf(“%f\n”,r);
}
double TestArray(double b[], int Size)
{double s=0;int i;for( i=0; i<Size; i++)s += b[i];b[4]=0;return(s);
}
运行结果:
Result = 15.5↙
r = 10.4↙
地址传递方式
函数与函数之间数组的地址传递方式是将调用函数中的实参数组的起始地址传递给被调用函数的指针变量形参。因此,被调用函数中对形参地址的目标操作,相当于对实参本身的操作,将直接改变实参数组的值。地址传递方式,实参应该为数组的指针,而形参应为同类型的指针变量。另外,数组的地址传递方式不仅要把实参数组的指针作为参数传递给函数,同时还需要传递数组的长度。
函数间数组地址传递方式的例子。
#include <stdio.h>
double TestArray(double *pa, int Size); //函数说明
int main(void)
{double a[5]={1.1, 2.1, 3.1, 4.1, 5.1}, r=0;r=TestArray(a,5); //将数组传递给函数 printf(“%.2f\n”,r);
}
double TestArray(double *pa, int Size) //形参为一个指针
{int i; double s=0;for(i=0; i<Size; i++) //注意:这里的pa[i]就是a[i]s += pa[i];return(s);
}
运行结果:
Sum=15.5 ↙
指针函数
指针函数是指一个函数的返回值为地址量的函数。通常一个函数都有返回值的数据类型。如果一个函数没有返回值,则该函数是一个无值型函数。指针函数只不过是一个函数的返回值是某一数据类型变量的地址。
指针函数的定义的一般形式如下:<数据类型> *<函数名称>(<参数说明>){语句序列;}
其中
-
<数据类型> 、<函数名称>、<形式参数说明> 等与一般函数定义相同;
-
在<函数名称>之前的*符号,说明该函数返回 一个地址量。
例:编写函数实现字符串的倒序输出。#include <stdio.h>char *InverseString(char *pstr); int main(){char str[6]={'a', 'b', 'c', 'd', 'e', '\0'} ;printf(“%s\n”,InverseString(str));} char * InverseString(char *pstr) //定义一个指针函数 { static char text[128];int len=0;int i;while( *(pstr+len) != ‘\0’) //求字符串的长度len++;for(i= len-1; i>=0; i-- )text[len-i-1] = *(pstr+i); //实现字符串的位置倒序;text[len]=’\0’;return(text); }运行结果:edcba↙
函数指针
函数指针是用来存放函数的地址,这个地址是一个函数的入口地址,而且是函数调用时使用的起始地址。当一个函数指针指向了一个函数,就可以通过这个指针来调用该函数,函数指针可以将函数作为参数传递给其他函数调用。
函数指针变量说明的一般形式如下:
<数据类型> (*<函数指针名称>)(<参数说明列表>);
其中
-
<数据类型>是函数指针所指向的函数的返回值类型;
-
<函数指针名称>符合标识符命名规则
-
<参数说明列表>应该与函数指针所指向的函数的形参说明保持一致;
-
(*<函数指针名称>)中,*说明为指针()不可缺省,表明为函数的指针。
#include <stdio.h>int test(int a, int b, int (*pFunt)(int m,int n)); int Plus(int a,int b); //函数说明 int Minus(int , int ); //函数说明,缺省形式参数名称 int main(void){int x=5, y=8;int (* pFunc)(int a, int b); //说明一个名称为pFunc的函数指针pFunc=Plus; //把函数Plus的地址赋给函数指针pFunc;printf(“%d\n”, (*pFunc)(x,y) );pFunc=Minus; //把函数Minus的地址赋给函数指针 pFunc;printf(“%d\n”, (*pFunc)(x,y) );printf(“%d\n”, test(15,5,Plus) ); //把函数Plus作为实参调用testprintf(“%d\n”, test(15,5,Minus) );//把函数Minus作为实参调用test}int Plus(int a,int b) //简单的加法函数{ return (a+b); }int Minus(int a,int b) //简单的减法函数{ return (a-b); }int test(int a,int b, int (*pFunt)(int m,int n)) //简单的测试函数指针的函数{ return ( (*pFunt)(a,b)); }
函数指针数组
函数指针数组是一个保存若干个函数名的数组。
一般形式如下:
<数据类型> ( * <函数指针数组名称> [<大小>] ) ( <参数说明列表> );
其中,<大小>是指函数指针数组元数的个数,其它同函数指针。
函数指针数组应用的一个例子。
#include <stdio.h>
int Plus(int a, int b); //计算加法函数的说明
int Minus(int a, int b); //计算减法函数的说明
void main(void)
{int (*pFunc[2])(int a,int b); int i;pFunc[0] = Plus; pFunc[1] = Minus;for( i=0; i<2; i++){printf(“%d\n”, (* pFunc[i])(15,85) );
}int Plus(int a, int b)
{return(a+b);
}int Minus(int a, int b)
{return(a-b);
}
递归函数
所谓递归函数是指一个函数的函数体中直接调用或间接调用了该函数自身的函数。这里的直接调用是指一个函数的函数体中含有调用自身的语句,间接调用是指一个函数在函数体里有调用了其它函数,而其它函数又反过来调用了该函数的情况。
递归函数调用的执行过程分为两个阶段:
递推阶段:从原问题出发,按递归公式递推从未知到已知,最终达到递归终止条件。
回归阶段:按递归终止条件求出结果,逆向逐步代入递归公式,回归到原问题求解。
例:
#include <stdio.h>
double Factorial(int n); //递归函数说明
int main(void)
{double r=Factorial(5); //调用函数Factorial并将返回值 赋给rprintf(“5!=%f\n”,r);return 0;
}
double Factorial(int n) //定义求n!函数,要求n大于等于零
{if(n<=1) return (1); //递归函数终止条件return ( n*Factorial(n-1) ); // Factorial函数的函数体中调用了 Factorial函数
}
运行结果:
5!=120↙