函数知识点与例题.docx
《函数知识点与例题.docx》由会员分享,可在线阅读,更多相关《函数知识点与例题.docx(22页珍藏版)》请在冰豆网上搜索。
![函数知识点与例题.docx](https://file1.bdocx.com/fileroot1/2022-10/29/c97aa580-e42d-421e-b088-c3c7954bdc27/c97aa580-e42d-421e-b088-c3c7954bdc271.gif)
函数知识点与例题
6.1 函数定义
在C程序设计中,将完成指定功能的C代码定义成函数,变成逻辑上一个相对独立的程序单位。
函数定义需要指明函数返回值的类型、函数名、函数的形式参数(常简称形参)和函数体(包括说明和定义及语句序列)。
函数定义的一般形式为
存储类型说明符 数据类型说明符 函数名(形式参数表)
形式参数说明序列
{
说明和定义部分
执行语句序列
}
存储类型说明符或省缺,或为static。
省缺表示一个全局函数,static表示一个静态函数,只供同一源程序文件中的函数使用。
数据类型说明符用来指定函数返回值类型,可以是基本数据类型、某种指针类型、结构类型等。
但不可以是数组类型。
特别当函数不返回结果时,可用void明确指明函数不返回值。
数据类型说明符也可省缺,省缺被默认为返回int型值。
函数名是一个标识符。
形式参数表是用远号分隔的若干形式参数,用不同的标识符指明各形式参数的名。
形式参数说明序列用来说明各形式参数的数据类型,相同数据类型的形式参数可以一起说明。
现在编写C程序的习惯是形式参数说明序列直接放在形式参数表中,即在形式参数说明表中顺序列出各形式参数的数据类型和形式参数的名称。
如是这样,一般形式的第一行全部内容称为函数头,也称为函数模型。
特别情况,函数可能不设形式参数,也就没有形式参数表和形式参数说明序列。
但函数名后的一对圆括号是不可以没有的。
一对花括号括住的部分称为函数体,函数体包括类型说明、变量定义和函数的执行语句序列。
在函数体内可以有return语句终止函数的执行。
如函数有返回值类型,则return语句中一定要有表达式,作为函数调用的返回值。
6.2 函数调用
函数被定义以后,凡要实现函数功能的地方,就可简单地通过函数调用来完成。
按函数调用在程序中的作用,有两种不同类型的应用:
(1)函数调用只是利用函数所完成的功能。
此时,将函数调用作为一个独立的语句。
其调用的一般形式为
函数名(实际参数表);
这种应用不要求或程序不利用函数的返回值。
如程序中经常调用格式输入函数scanf()和格式输出函数printf()等。
(2)函数调用是利用函数的返回值。
其调用的一般形式为
函数名(实际参数表)
这种应用是利用返回值继续进行表达式的计算,或输出函数返回值等。
函数调用时提供的实际参数按它们出现的顺序与函数定义中的形式参数—一对应,并要求实际参数类型与其对应的形式参数类型相一致。
一般情况下,函数调用应为函数定义中的每个形式参数提供实际参数,当有多个实际参数时,实际参数之间用逗号分隔。
函数调用的执行过程描述如下:
(l)为函数的形式参数分配内存空间;
(2)计算实际参数表达式的值,并将实际参数表达式的值赋给对应的形式参数;
(3)为函数的局部变量分配内存空间;
(4)执行函数体内的语句序列;
(5)函数体执行完成,或执行了函数体内的return语句(若return语句带表达式,则计算出该表达式的值,并以此值作为函数的返回值)后,释放为这次函数调用分配的全部内存空间;
(6)将函数值(如果有)返回到函数调用处继续执行。
下面以简单的程序例子说明函数调用的执行过程。
【例6.l】函数调用时,由实际参数向函数形式参数传递值的示意程序。
#include
doublex,y,d;
doublemin(doublea,doubleb)
{doubletemp;
temp=a>b?
b:
a;
returntemp;
}
voidmain()
{printf("Enterx,y.\n");
scanf("%lf%lf",&x,&y);
d=min(x,y);
printf("MIN(%.3f,%.3f=%.3f\n",x,y,d)
}
以上示意程序的大致执行过程如下:
首先执行主函数的第一个语句,调用格式输出函数输出提示信息。
接着调用格式输入函数,等待用户输入数据。
用户看到程序输出的提示信息,输入数据,输入的数据被格式输入函数所接受,并将输入数据译成内部形式后,存入变量X和y。
接着执行赋值语句,求右瑞表达式的值。
该表达式以x和y的值为实际参数,调用函数main()。
对函数min()的调用发生时,系统先保留好控制的返回点。
在执行被调用函数min()之前,先为函数的形式参数a和b分配存储单元,并以它们对应的实际参数表达式的植给它们赋初值。
接着为函数内部的变量(称为局部变量)分配存储单元。
之后才开始执行被调用函数体中的语句。
执行完函数体的语句,或执行了return语句,函数准备返回。
在返回之前先将形式参数和局部变量所占用的存储单元全部释放。
函数返回时,将函数的返回值带回调用处,从原先保留的控制返回点,继续执行,将函数调用的返回值存于变量d,输出结果,结束程序。
综上所述,函数调用时,系统要做许多辅助工作,函数调用时发生的数据传递最主要的是实际参数向形式参数传递数据和函数的返回值传递给调用处。
为正确编写函数,实现函数调用所希望的要求,需正确了解以下几项内容:
(1)当函数执行return语句或执行完函数体的语句序列后,函数的这次调用就执行结束,随之将控制返回到函数调用处继续执行。
(2)函数的返回值是通过执行return语句时,计算return之后的表达式值而获得的。
如果函数不提供返回值,则return语句不应包含表达式。
(3)如果函数有返回值,则应有确定的类型,并在函数定义时指明。
同时,return语句的表达式类型应与函数定义中指明的返回值类型相一致。
(4)为了明确指明函数不提供返回值,建议在函数定义时,在函数名之前写上void。
并在这样的函数体内,所有的return语句都不应该带表达式。
6.3 函数说明
C函数都是外部的,一般来说,任一函数都能被其它函数调用。
而一个函数要调用另一个函数,应知道被调用函数的一些有关如何正确调用的信息。
调用函数与被调用函数之间在程序正文中可能会存在以下几种情况。
(l)调用同一程序文件中前面已定义的函数。
(2)调用处于同一程序文件后面定义的函数。
(3)调用别的程序文件中定义的函数。
对于第一种情况,因在函数调用处,被调用函数的详细信息已被编译程序所接受,在函数定义之后调用前面已定义的函数,能方便地检查调用的正确性。
对于后两种情况,这时因被调用函数的信息还未被编译程序所接受,不能检查函数调用的正确性,所以在调用之前需对被调用函数有关调用的一些信息作出说明。
如函数的返回值类型、函数名和函数有关形式参数的个数及其类型等。
这样的说明称作函数说明。
函数说明的一般形式为
存储类型说明符数据类型说明符函数名(形式参数说明表);
其中存储类型说明符可以省缺,或写成extern。
形式参数说明表可以为空,也可以顺序列出各形式参数的类型,同样也可以顺序列出各形式参数的类型和形式参数的名。
6.4 函数调用中的数据传递方式
函数调用时,调用处与被调用函数之间会有数据传递发生。
在C程序中,函数调用的数据传递方式有四种:
实际参数的数据值传递给形式参数(值传递方式)、实际参数的指针值传递给形式参数(地址传递方式)、函数以返回值传递给调用环境(返回值方式)、调用环境与被调用函数共用全局变量(全局变量传递方式)。
在地址传递方式中,实际参数可以是传递一般变量的指针、数组某元素的指针、字符串某字符指针等。
1.实际参数向形式参数传递非指针数据
调用带形式参数的函数时,调用处将实际参数的值传递给被调用函数的形式参数。
在此要特别说明以下几点:
(l)函数调用时实际参数为对应的形式参数提供初值,实际参数表达式的值是在执行函数体之前计算的,函数调用中的实际参数可以是常量、变量或是一般的表达式。
(2)C语言规定,实际参数表达式对形式参数的数据传递是“值传递”的,是单向传递。
如实际参数也是变量,则实际参数变量与形式参数是不同的变量,实际参数变量的值传给形式参数,而不能由形式参数直接传回给实际参数。
在函数执行过程中,形式参数变量的值可能被改变,但这改变对原先与它对应的实际参数变量没有影响。
2.实际参数向形式参数传递指针
实际参数向形式参数传递变量的指针
函数可以设置指针类型的形式参数,调用带指针类型形式参数的函数时,对应指针形式参数的实际参数必须是相同类型的指针(如胡同类型的某变量的指针),指针形式参数变量从实际参数处得到某变量的指针。
指针形式参数对于函数来说有特别的作用,它使函数得到了调用环境中某变量的地址,函数就可用这个地址间接访问函数之外的变量。
因此,指针类型形式参数为函数改变调用环境中的数据对象提供了手段。
如希望函数能通过形式参数改变任意指定变量的值,需要在三个方面协调一致:
(1)首先,函数应设置指针类型的形式参数;
(2)其次,函数体必须通过指针形式参数间接访问变量,或引用其值或修改其值;
(3)最后,调用函数时,要以欲改变值的变量的指针为实际参数调用函数。
实际参数向形式参数传递数组元素的指针
为了能使函数处理不同的成组变量,应向形式参数传递数组元素的指针,最通常的情况是数组首元素的指针。
由于数组名能代表数组首元素的指针,所以常用数组名实际参数给形式参数传递数组首元素的指针。
例如,用于求数组前n个元素和的函数sun(),这个函数被正确地设置有两个形式参数:
一个形式参数是数组元素的指针;另一个整型的形式参数用于指定求和数组的元素个数。
【例6.2】求数组元素和的函数。
intsum(int*a,intn)
{inti,s;
for(s=i=0;i s+=a[i];
returns;
}
利用函数sum(),如有以下变量定义:
intx[]={1,2,3,4,5},i,j;
则语句
i=sum(x,5);j=sum(&x[2],3);
printf("i=%d\nj=%d\n",i,j);
将输出:
i=15
j=12
函数调用sum(x,5)将数组x的首元素地址(&x[0])传送给形式参数a;函数调用sum(&x[2], 3)将数组x的元素x[2]的地址(&x[2])传送给形式参数a,而x[2]的地址就是数组元素段x[2]、x[3]、x[4]的开始地址。
为了明确指明形式参数是数组元素的指针,形式参数的类型可以指定为数组类型的。
如改写后的函数sum()定义如下:
intsum(inta[],intn)
{inti,s;
for(s=i=0;i s+=a[i];
returns;
}
对于数组类型的形式参数来说,函数被调用时,与它对应的实在数组由多少个元素是不确定的,可能会对应一个大数组,也可能会对应一个小数组,甚至会对应数组中的某一段。
所以在数组形式参数说明中,形式参数数组不必指定数组元素的个数。
任何数组形式参数说明:
类型 形式参数名[]
都可改写成:
类型 *形式参数名
函数形式参数也是函数的一种局部变量,指针形式参数就是函数的指针变量,函数sum()的定义又可改写成如下形式:
intsum