第七章函数
考核知识点
●库函数的正确调用
●函数的定义方法
●函数的类型和返回值
●形式参数与实际参数,参数值的传递
●函数正确调用,嵌套调用和递归调用
●局部变量和全局变量
●变量的存储类别(自动、静态、寄存器、外部),变量的作用域和生存周期]
●内部函数与外部函数
重要考点提示
●处理字符数组的标准函数的调用
●用户自定义函数的声明和定义
●函数的递归调用
●对变量的作用域、有效期和可见性的理解
●函数的参数传递
●函数返回值的类型
7.1概述
在前面各章的例子及读者自己编写的C语言程序中都用到了以main()开头的主函数,并且在程序中频繁地调用了C语言提供的用于输入输出的库函数(scanf()和printf())。
一般情况下,一个较大的程序应分为若干个小的程序模块,每一模块专门用来实现一个特定的功能。这样做的实质是把一个大的工程拆分、简化为粘的部分。各个部分独立完成某项工作。在所有的高级语言中都有子程序的概念,用于实现模块的功能。在C语言中,子程序的作用是由函数完成的。一个C程序可
由一个主函数和若干个其他函数构成,并且只能有一个主函数。由主函数来调用其他函数,其他子函数之间也可以相互调用。
C程序的执行总是从main()函数开始。调用其他函数完毕后,程序流程式回到main()函数,继续执行主函数中的其他语句,直到main()函数结束,则整个程序的运行结束。main()函数是由系统定义的,所有的函数都是平行的,即在函数定义时它们是互相独立的,函数之间并不存在从属关系。也就是说,函数不能嵌套定义,函数之间可以互相调用,但不允许调用main()函数。
从用户的使用角度看,函数有两种:
⑴标准函数,即库函数。这些函数由系统提供,可以直接使用。
⑵自定义的函数。用以解决用户需要时设计定义的函数。
从函数的形式看,函数分为两类:
⑴无参函数。
⑵有参函数。
7.2库函数
1.库函数
C语言提供了丰富的库函数,这些函数包括了常用的数学函数,如求平方根的sqrt()函数,对字符和字符串进行了处理的函数,进行输入输出处理的各种函数等。
调用C语言标准库函数时要求使用“include”命令对每一类库函数进行文件包含,即在主调函数中需要调用库函数时,应在主调函数的声明部分用#include命令把该库函数的头文件名包含进来。
例如,调用有关字符串处理的库函数时,要求程序在调用字符串处理函数前包含以下命令:
#include <string.h>
对库函数的一般调用形式为:
函数名(参数表);
在C语言中,库函数的调用可以以两种形式出现。
⑴在表达式中调用,例如:
y=sin(x);
在这里,函数的调用出现在赋值号右边的表达式中。
⑵作为獐的语句完成某种操作,例如以下调用:
printf(“请输入两个整数:”);
在这里,调用库函数输出提示性语言。
7.3函数定义的一般形式
1.函数的定义
C语言函数定义的一般开展如下:
函数返回值的类型名函数名(类型名形式参数1,类型名形式参数2,...)
{
说明部分;
语句部分;
}
说明:函数名和各个开展参数都是由用户命名的合法标识符,与普通变量名的定义规则相同。在同一程序中,函数名必须唯一,不能出现重名的情况。形式参数名只要在同一函数中唯一即可,由于形式参数的作用域不相同,因此形式参数名可以与其他函数中的变量名同名。C语言规定,不能在一个函数内部再定义函数,也就是说函数不能嵌套定义。
(1)若在函数的首部省略了函数返回值的类型名,可以把函数首部写成:
函数名(类型名形式参数1,类型名形式参数2,……,类型名形式参数n)(2)紧跟在函数名之后的圆括号中的内容是形式参数和类型说明表,在每个形参之前都要有类型名,以标识形式参数的类型。各形参的定义之间用逗号分隔。
例如,求两整数和的函数:
int add(int a,int b)
{
int t; /*函数体中声明部分*/
t=a+b;
return t;
}
若所定义的函数没有形参,函数名后的一对圆括号依然不能省略。本例中函数体中的语句是用来完成求和的功能。在某些情况下,函数体可以是空的,例如:
fun()
{}
该函数中没有任何语句,什么工作也不做,没有任何实际作用。之所以要在主调函数上
这样写,是为了表明此处要调用一个函数,而现在这个函数的具体功能可能还没有设计好,没有起作用,等以后扩充函数功能时补充上即可。
⑶在函数体中,除形参外,用到的其他变量必须在说明部分进行定义,这些变量(包括形参)只在函数被调用时才被分配内存单元,当退出函数时,这些临时开辟的存储单元全部被释放掉,即在该函数体内部定义的变量都将不存在。因此,这些变量只在函数体内部起作用,与其他函数体内的变量并不相关。
7.4函数参数和函数返回值
1.开展参数和实际参数
在程序中调用函数时,绝大多数情况下,主调用函数和被调函数之间会发生数据传递关系,这就要用到前面提到的有参函数。在定义函数时,函数名括号中的变量称为“形式参数”(简称“形参”);在主调函数中,函数名后面括号中的参数(可以是一个表达式)称为“实际参数”(简称“实参”)。
说明:
⑴实参可以是常量、变量或表达式。
⑵在被定义的函数中必须指定形参类型。
⑶实参与形参的类型应相同或赋值相兼容。
⑷C语言规定,实参变量对形参变量的数据传递是“值传递”,即单向传递。只能由实参传给形参,而不能由形参返回来级实参。在内存中,实参单元与形参单元是不同的单元。
⑸在调用函数时,给形参分配存储单元,并将实参对应的值传递给形参。调用结束后,形参单元被释放,实参单元仍保留并维持原值。
2.函数的返回值
函数的返回值就是通过函数调用使主调函数能得到一个确定的值。函数的值通过return 语句返回,return语句的形式如下:
return 表达式;
或return(表达式);
或return;
return语句中的表达式的值就是所求的函数值。此表达式值的类型必须与函数首部所说明的类型一致。若类型不一致,则以函数值的类型为准,由系统自动进行转换。
7.5 函数的调用
1.函数调用的一般形式
函数调用的一般形式为:
函数名(实参表列);
函数的调用可以分为调用无参函数和调用有参函数两种,如果是调用无参函数,则不用“实参表列”,但括号不能省略。在调用有参函数时,若实参列表中有多个实参,各参数间用逗号隔开。实参与形参要求类型一致。
2.函数调用的方式
⑴函数语句。把函数调用作为一个语句,这时该函数只需要完成一定的操作而不必有返回值。
⑵函数表达式。当一个函数出现在一个表达式中,该表达式就被称为函数表达式。因为要参与表达式中的计算,所以要求该函数有一个确定的返回值提供给表达式。
⑶函数参数。函数调用作为了一个函数的实参。
C语言中,调用函数和被调用函数之间的数据可通过3种方式传递。
⑴实参与形参之间进行数据传递。
⑵通过return 语句把函数值返回到主调用函数中。
⑶通过全局变量。
3.函数的说明
C 语言中,除了主函数外,对于用户定义的函数要遵循先定义后使用的规则。把函数的定义放在调用之后,应该在调用之前对函数进行了说明(或函数原型说明)。函数说明的一般形式如下:
类型名 函数名(参数类型1,参数类型2,...,参数类型n )
如 int add(int,int);
或
类型名 函数名(参数类型1 参数名1,参数类型2 参数名2,...,参数类型n 参数名n );
此处的参数名完全是虚设的,它们可以是任意的用户标识符,既不必与函数首部中的形参名一致。又可以与程序中的任意用户标识符同名,实际上参数名常常可以省略。函数说明语句中的类型名必须与函数返回值的类型一致。
函数说明可以是一条独立的语句。对函数进行说明,能使C 语言的编译程序在编译时进行有效的类型检查。当调用函数时,若实参的类型与形参的类型不能赋值兼容而进行非法转换,C 编译程序将会发现错误并报错;当实参的个数与形参的个数不同时,编译程序也将报错。
4.函数说明的位置
一个函数在所有函数的外部,如在被调用之前说明,则在说明后的所有位置上都可以对该函数进行调用。如在main()函数内部进行了说明,则只能在main()函数内部才能识别该函数。
字符串函数连接“说明”与“定义”是两个不同的概念。
7.6函数的嵌套调用与递归调用
1.函数的嵌套调用
C 语言的函数定义都是独立的、互相平行的,C 语名是不允许嵌套定义函数的,即一个函数内不能定义另一个函数。但可以嵌套调用函数,即在调用一个函数的过程中,又调用另一个函数,如图7-1所示。
()
B ()
结束
函数B
()C
()
函数C ()
图7-1
函数的嵌套调用 2.函数的递归调用
在调用一个函数的过程中又出现直接或间接地调用该函数本身,称为函数的递归调用。允许函数的递归调用是C 语言的特点之一。
当一个问题在采用递归法解决时,必须符合以下3个条件:
⑴可以把要解决的问题转化为一个新的问题。而这个新的问题的解决方法仍与原来的解决方法相同,只是所处理的对象有规律地递增或递减。
⑵可以应用这个转化过程使问题得到解决。
⑶必须要有一个明确的结束递归的条件。
当函数自己调用自己时,系统将自动把函数中当前的变量和形参暂时保留起来,在新一轮的调用过程中,系统将为本次调用的函数所用到的变量和形参,开辟新的存储单元。因此,递归调用的层次越多,同名变量所占的存储单元刀就越多。当本次调用的函数运行结束时,系统将释放本次调用所占的存储单元。当程序执行的流程返回到上一层的调用点时,同进取用进入该层函数中的变量和形参所占用的存储单元中的数据。
7.7数组作为函数参数
1.数组元素作为函数实参
数组元素可以作为函数的实参,其用法与变量相同。数组名也可以用为实参和形参,传递的是整个数组。
2.数组名可以作为函数参数
可以用数组名作为函数参数,此时实参与形参都应用数组名,此时的数组名是整个数组的首地址。
7.8 全局变量和局部变量
在C语言中,用户命名的标识符都有一个有效的作用域。所谓标识符的“作用域”就是指程序中的某一部分,在这部分中,该标识符是有定义的,可以被C编译和连接程序所识别。在一个函数内定义的变量,不能在其他函数中引用。显然,变量的作用域与其定义语句在程序中出的位置有直接的关系,据此变量可以划分为局部变量和全局变量。
1.局部变量
在一个函数内部定义的变量,它们只在本函数范围内有效,即只有本函数才能使用它们,其他函数不能使用这些变量,这些变量称为局部变量。不同函数中可以使用相同名字的局部变量,它们代表不同的对象,在内存中占不同的单元,互不干扰。
2.全局变量
在函数之外定义的变量称为外部变量,外部变量是全局变量。全局变量可以为本文件中其他函数所共用,它的有效范围从定义变量开始到文件结束。
提示:在同一个源文件中,外部变量与局部变量同名,则在局部变量的作用范围内,外部变量被“屏蔽”,即它不起作用。
7.9 变量的存储类别
从变量值存在的时间(即生存期)来看,变量的存储方式分为静态存储方式和动态存储方式。所谓静态存储方式是指在程序运行期间分配固定存储空间的方式,而动态存储方式是在程序运行期间根据需要动态分配空间的方式。
在内存中用户使用的空间可以分为程序区、静态存储区和动态存储区3个部分。数据分别被存放在静态和动态存储区中。静态存储区存放的是全局变量,在程序开始执行时就给全局变量分配存储区,程序执行过程中它们占据固定的存储单元,程序执行完毕这些存储单元就被释放。
每一个变量和函数所具有的属性是:数据的存储类别和数据类型。所谓的存储类别指的是数据在内存中存储的存储方法,其可分为两类:静态存储类和动态存储类。具体包括自动(auto)、静态(static)、寄存器(regisiter)和外部(extern),共4种。
1.auto变量
当在函数内部或复合语句内定义变量时,如果没有指定存储类别,或使用了auto说明
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论