目录
八、函数
8.1概述
8.2函数定义的一般形式
无参函数
有参函数
空函数
8.3函数参数和函数的值
形式参数和实际参数
函数的返回值
8.4函数的调用
函数调用的一般形式
函数调用的方式
1.函数语句
2.函数表达式
3.函数参数
对被调用函数的声明和函数原型
8.5函数的嵌套调用
8.6函数的递归调用
八、函数
8.1概述
一个较大的程序一般应分为若干程序模块,每一个模块用来实现一个特定的功能。所有高级语言中都有子程序这个概念,用子程序实现模块的功能。在C语言中,子程序的作用是由函数来完成的。一个C程序可由一个主函数和若干函数来构成的。由主函数调用其他函数,其他函数也可以相互调用。同一个函数可以被一个或者多个函数调用任意多次。
在程序开发中,常将一些常用的功能模块编写成函数,放在公共函数库供大家选用。所以,我们要善于利用函数,以减少重复编写程序段的工作量。
8.2函数定义的一般形式
无参函数
定义无参函数的一般形式:
类型标识符 函数名 ()
{
声明部分
语句部分
}
有参函数
定义有参函数的一般形式:
类型标识符 函数名 (形式参数表列)
{
声明部分
语句部分
}
例如:
int max(int x, int y)
{int z; //函数体中的声明部分z = x>y?x:y;return z;
}
如果在定义函数时不指定函数类型,系统会隐含指定函数类型为int型。因此上面定义的max函数左端的int可以省写。
空函数
空函数的定义形式为:
类型说明符 函数名()
{ }
例如:
int dummy(){}
8.3函数参数和函数的值
形式参数和实际参数
在调用函数时,大多数情况下,主函数和调用函数之间有数据传递的关系。这就是前面提到的有参函数。
在定义函数时函数名后面括号中的变量名称为“形式参数”,简称“形参”。
在主函数中调用一个函数时,函数后面括号中的参数(可以是一个表达式)称为“实际参数”,简称“实参”。
调用函数时的数据传递
#include<stdio.h>
int main()
{int max(int x, int y); //对max函数声明int a,b,c;scanf("%d%d",&a,&b);c = max(a,b);printf("max is %d\n",c); return 0;} int max(int x, int y)
{int z;z = x>y?x:y;return z;
}
关于形参和实参的说明:
-
在定义函数中指定的形参,在未出现函数调用时,它们并不占内存中的存储单元。只有在发生函数调用时,函数max中的形参才被分配到内存单元,在调用结束后,形参所占的内存单元也被释放。
-
实参可以是常量、变量或表达式。例如:max(3,a+b),但是要求他们有确定的值,在调用时将实参的值赋给形参。
-
在被定义的函数中,必须指定形参的类型。
-
实参和形参的类型应相同或赋值兼容。
-
在C语言中,实参向形参的数据传递是“值传递”,单向传递,只由实参传给形参,而不能有形参传回来给实参。在内存中,实参单元与形参单元是不同的单元。
在调用函数时,给形参分配存储单元,并将实参对应的值传递给形参,调用结束后,形参单元被释放,实参单元仍保留并维持原值。因此,在执行一个被调用函数时,形参的值如果发生改变,并不会改变主调函数的实参的值。
函数的返回值
通常,希望通过函数调用使主调函数能得到一个确定的值,这就是函数的返回值。下面对函数值作一些说明:
(1)函数的返回值是通过函数中的return语句获得的。return语句将被调用函数中的一个确定的值带回主调函数中去。如果需要从被调用函数带回一个函数值(供主函数使用),被调用函数中必须包含一个return语句。如果不需要从被调函数带回函数值可以不要return语句。
return语句后面的括号也可以不要,如“return z”等价于“return (z)”。
return后面的值可以是一个表达式。
(2)函数值的类型。函数的返回值属于某一确定的类型,所以,应当在定义函数时指定函数值的类型。
在C语言中,凡不加类型说明的函数,自动按整型处理。
(3)在定义函数时指定的函数类型一般应该和return语句中的表达式类型一致。
如果函数值的类型和return语句中表达式的类型不一致,则以函数类型的为准。对数值型数据,可以自动进行类型转换。即函数类型决定返回值的类型。
返回值类型于函数类型不同。将上面的代码稍作改动(注意:是变量的类型改动)
#include<stdio.h>
int main()
{int max(float x, float y); //对max函数声明float a,b;int c;scanf("%f%f",&a,&b);c = max(a,b);printf("max is %d\n",c); return 0;} int max(float x, float y)
{float z; z = x>y?x:y;return z;
}
//输入 1.5 2.5
//输出:max is 2
解释:函数max定义为整型,而return语句中的z为实型,二者不一致。按上述规定,现将z转换为整型,然后max(x,y)带回一个数值2返回主调函数main。如果将main函数中的c定义为实型,用%f格式输出,也是输出2.000000。
(4)对于不带回值的函数,应当用“void”定义函数为“无类型”(或称“空类型”)。这样,系统就保证不使函数带回任何值,即禁止在调用函数中使用被调函数的返回值。此时,在函数体中不得出现有返回值的return语句。
8.4函数的调用
函数调用的一般形式
函数名(实参表列)
-
如果是调用无参函数,则:实参表列“可以没有,但括号不能省略。
-
如果实参表列包含多个实参,则各个参数间用逗号隔开。
-
实参和形参的个数应相等,类型应匹配。
-
实参和形参按顺序对应,一一传递数据。
函数调用的方式
按函数在程序中出现的位置来分,可以有以下3种函数调用方式。
1.函数语句
把函数调用作为一个语句。这时不要求函数带回值,只要求函数完成一定的操作。
max();
2.函数表达式
函数出现在一个表达式中,这种表达式称为函数表达式。这时要求函数带回一个确定的值一参加表达式的计算。
c = 2*max(a,b); //max只是表达式的一部分
3.函数参数
函数调用作为一个函数的实参。例如:
//1.
m = max(a,mx(b,c));
//2.
printf("%d",max(a,b));
函数调用作为函数的参数,实质上也是函数表达式形式调用的一种,因为函数参数本来就要求表达式形式。
对被调用函数的声明和函数原型
在一个函数中调用另一个函数(即被调用函数)需要具备的条件如下。
-
首先调用的函数必须是已经存在的函数(是函数库或者用户自己定义的函数)。
-
如果使用库函数,还应该在本文件开头用#include命令将调用有关函数时所需用到的信息“包含”到本文件中。
-
如果使用用户自己定义的函数,而该函数的位置在调用它的函数(即主调函数)的后面(在同一文件中),应该在主调函数中队被调用的函数作声明。
函数原型的一般形式有两种:
-
函数类型 函数名(参数类型1,参数类型2,··· 参数类型n);
-
函数类型 函数名(参数类型1 参数名1,参数类型2 参数名2, ··· ,参数类型n 参数名n);
8.5函数的嵌套调用
C语言的函数定义是互相平行、独立的,也就是说,在定义函数时,一个函数内不能包含另一个函数。
C语言不能嵌套定义函数,但可以嵌套调用函数,也就是说,在调用一个函数的过程中,又调用另一个函数。
8.6函数的递归调用
在调用一个函数的过程中又出现直接或间接地调用该函数本身,称为函数的递归调用。C语言的特点之一就是在于允许函数的递归调用。例如:
int f(int x)
{int y,z;z=f(y);return (2*z);
}
递归调用会无终止的自身调用。而程序中是不应该出现这种情况的,而应出现有限次数、有终止的递归调用,这可以用if语句来控制,只有在某一条件成立时才继续执行递归调用;否则就不再继续。
声明:本文章为个人学习笔记,资料整理参考谭浩强《C程序设计(第三版)》如有错误,欢迎大家指正!