根据模块化程序设计的原则,一个较大的程序一般要分为若干个小模块,每个模块实现一个比较简单的功能。在c语言中,函数是一个基本的程序模块。
(1)函数的基本概念:
1)基本介绍:
任何一个结构化的程序都可以用三种基本结构组成:顺序结构、选择结构和循环结构,为了利用这三种结构编写程序,通常采用自顶向下,逐步细化和模块化的程序设计方法。
*函数是按规定格式书写的能完成特定功能的一段程序。
*c语言是以源文件为单位进行编译的,一个源文件由一个或多个函数组成。
*一个c程序由一个或多个源程序文件组成,可以利用c语言分别编译的特点,将源文件分别编译成目标文件,然后将这些目标文件链接到一起,形成可执行文件。
*函数与函数之间是相互独立的,没有从属关系,不能嵌套定义,但可以相互调用,主函数可以调用任何函数,而其他函数不能调用主函数。
*在c语言中,程序总是从主函数开始执行,调用完其他函数后,最终在主函数中结束,而不管主函数在程序中的位置如何。
2)函数的定义:
函数由函数名,参数,函数体组成。
*函数体中可以既无变量也无语句,但是不可以省略包含函数体的一对花括号,此时构成空函数。例如undo(){};空函数不从产生任何操作。在模块化程序设计中,往往首先设计基本模块,对一些次要功能的模块,可以设计成为空函数,使得程序具有完整的结构,以后再逐步填补这些函数。
编写函数,将一个给定的整数转化成相应的字符串后显示出来:
1 #include<stdio.h> 2 3 void toStr(int n){ 4 char string[10]; 5 int i=0; 6 if(n<0){ 7 putchar('-'); 8 n=-n; 9 } 10 while(n>0){ 11 string[i++]=n%10+'0';//将取出的整数加上ASCII码的字符'0',转化为字符 12 n=n/10;//从低位到高位依次存入 ,最终i的值要比字符数组的大小大1; 13 } 14 while(--i>=0){//所以这里要首先减1; 15 putchar(string[i]); 16 } 17 } 18 int main(){ 19 20 printf("The converted string: "); 21 toStr(-124); 22 return 0; 23 }
3)函数的调用
所谓函数的调用,是指一个函数(调用函数)暂停中断本函数的运行,转去执行其他函数的过程。被调用函数执行完之后,返回到调用函数中断处继续调用函数的执行,这是一个返回过程。在调用和返回的过程中,两个函数之间通常会发生信息的交换。
*第一种调用格式是以语句的形式调用函数,一般用于调用无返回值的函数。第二种调用格式是以表达式的形式调用函数,一般用于调用有返回值的函数。
例如 y=sin(x);和toStr('zifu');
*在c的标准中,实参表的求值顺序并不是确定的。有的系统按照自右向左的顺序计算,而有的系统则相反。
实参表求值顺序的影响:
1 #include<stdio.h> 2 3 int sum(int x,int y){ 4 return (x+y); 5 } 6 7 int main(){ 8 int a=6; 9 int b; 10 b=sum(a,a+=4); 11 printf("b=%d ",b); 12 return 0; 13 }
在上式中实参表按从右向左的方式晕眩,两个实参的值均为10,则最终结果为20。若系统按自左向右的顺序对实参表进行运算,则第一个实参为6,第二个是实参为10,程序的运行结果为16。
因此在实际中应避免这种不确定性。
例如:x=a+4;b=sum(a,x);
4)函数参数的传递方式:
*值传递
在函数调用时,实参将其值传递给形参,这种传递方式为值传递。在调用函数过程中,形参和实参具有不同的内存空间,实参将值传递给形参,形参的值如果发生变化并不会改变调用函数中实参的值。
*地址传递
指的是调用函数时,实参将某些量的地址传递给形参,这样实参和形参指向同一个内存空间。在地址传递下还可以是指针变量或数组名,其中,实参还可以是变量的地址。
5)函数的返回值:
return的作用有两个:一个是从调用的函数中退出并返回值,另一个是仅仅退出。return ();和return;另外带有返回值的return语句中的值可以没有圆括号包围。
若函数中没有return语句,函数也并非没有返回值,而是返回一个不确定的值。为了明确表示函数没有返回值,可以用void函数将函数定义为"空类型":
void output(int a,int b){
printf("%d",a+b);
}
如果函数既没有返回值又没有形参,可以定义为如下形式:
void 函数名(void){
}
6)例子:编写函数,求1+1/2+1/3+......+1/n的值,并在主函数中调用它:
1 #include<stdio.h> 2 3 double count(int n){ 4 int i; 5 double sum=0; 6 if(n<=0){ 7 printf("Data error!"); 8 return 0; 9 }else{ 10 for(int i=1;i<=n;i++){ 11 sum+=1.0/i;//这里不能写成1/i,否则将会进行整除运算 12 } 13 return sum; 14 } 15 } 16 17 int main(){ 18 int m; 19 double s; 20 printf("Please input the value: "); 21 scanf("%d",&m); 22 s=count(m); 23 printf("s=%6.2lf ",s); 24 return 0; 25 }
7)函数的原型声明
c语言要求函数先定义后使用,就像变量先定义后使用的那样。如果被调用函数的定义位于调用函数之前可以不用声明,而如果自定义的函数被放在调用函数的后面则就需要在函数调用之前加上原型声明。
函数的定义是对函数功能的描述,而声明则是在调用函数中根据此信息进行相应的语法检查。函数的声明可以忽略形参的名称,只保留形参类型。
(2)数组作为函数参数:
单个数组元素可以作为函数参数,此时是"值传递",而数组名作为函数实参时,向形参传递的是数组的首地址,是"地址传递"。
一维数组作为函数参数时可以不指定数组大小,而二维数组作为函数参数时可以不指定第一维的数组大小。
1)例子:编写函数int fun(char str[]),它的功能是判断字符串str是否是"回文数",如果是返回1,否则返回0:
1 #include<stdio.h> 2 3 int fun(char str[]){ 4 int n,k,flag=1; 5 for(n=0;str[n]!='