函数是C语言中实现特定功能的程序块,也叫程序模块。 每一个函数实现一个特定的功能,当其他函数需要这个功能时,调用该函数即可。
模块化程序设计的思路就是,事先设计好各个功能的模块,需要的时候采用组装的办法来简化程序的设计。
函数的操作,具体有: 函数的声明、函数的定义、函数的调用
函数的声明
把函数的有关信息通知编译系统,以便编译系统对程序进行编译时,知道它们是函数。具体信息包括:函数名、函数类型、函数参数的个数和类型。
函数的定义
“先定义,后使用”
定义函数包括以下内容:
- 函数的名字
- 函数的类型
- 函数参数的名字和类型
- 函数的具体操作,即实现什么功能
- 定义无参数的函数
类型名 函数名()
{
函数体
} - 定义有参数的函数
类型名 函数名(形式参数列表)
{
函数体
}
例:
int max(int x, int y) //函数类型为int整型,函数名为max,函数参数的名字为x、y,函数参数的类型为整型
//以下为函数的具体操作,此函数具体实现的功能为求两个数中的最大值
{
int z;
z = x>y ? x : y;
return z;
}
函数的调用
函数名(实参列表)
例:c = max(a, b);
形式参数与实际参数
对于有参数的函数,在函数定义阶段使用的参数为形式参数(例中的x和y),函数调用阶段使用的参数为实际参数(例中的a和b)
在函数的调用阶段,系统会将实参的值传递给被调用的函数的形参中,是**“值传递”**方式——数据传递的方向是从实参到形参,单向传递。形参与实参的数据类型应该相同,若有不同,实参的值会转换为形参的数据类型,再进行功能实现。
函数的调用过程
- 函数定义阶段到函数未被调用之前的这个阶段,函数中的形参不占内存中的存储单元。函数被调用时,形参才临时分配存储单元。
- 实参的值传递给形参。
- 执行函数功能,即运行函数体
- 通过return语句将函数运算的值返回调用函数。若函数不需要返回值,则函数的类型为void,且不需要return语句。
- 调用结束,形参单元被释放。实参的值从始到终是不会改变的,若形参的值发生改变,不会改变实参的值。这是因为形参和实参是两个不同的存储单元。
由以上调用过程可知,函数的调用必须在函数的声明之后。只有在声明之后,系统编译时才能识别到当前调用的是函数。
若被调用函数的定义在调用函数之前,则不用进行声明。因为函数定义时,系统以知道了这个函数的存在。
函数的声明与定义
函数的声明与定义的第1行基本相同,只是函数的声明多出了“;”号。
函数的声明是为了方便函数调用时,对其合法性进行检查。函数声明的是函数的原型
函数的定义是对函数功能的确定。函数的定义显然不在声明部分的范围内。
函数的参数
数组元素作为函数的实参
数组元素是可以作为函数的实参的,但数组元素不能作为函数的形参。
因为形参的存储单元是函数被调用时临时分配的,而数组是一个整体,在内存中占一串连续的存储单元,所以形参不可能为单个数组元素分配存储单元。但数组元素的值是可以单独分配存储单元进行存储的(单个的数组元素与单个变量的概念是一样的)。所以数组元素可以作为函数的实参。
数组名作为函数的参数
函数的数组名即可以作为函数的实参,又可以作为函数的形参。
形参数组可以不指定大小,在定义数组是在数组后跟一个空的方括号即可。
如:float average(float array[])
函数的变量
变量的声明和定义
定义性声明:简称定义,需要建立存储空间。
引用性声明:简称声明,不需要建立存储空间。
int a; //既是定义,又是声明
extern a; //只是声明
-
按作用域分
-
按变量的生存期分
-
从变量值存放的位置来分
局部变量和全局变量(作用域)
-
局部变量
函数内部定义的变量、复合语句内定义的变量、形参都是局部变量。
函数内部定义的变量,只在本函数范围内有效;复合语句内定义的变量,只在本复合语句范围内有效;形参是另一种形式的函数内部变量。 -
全局变量
在函数外部定义的变量称为外部变量,外部变量是全局变量。
全局变量的有效范围是从定义变量的位置开始,到本源文件结束。 -
不建议频繁使用全局变量的原因
- 全局变量全程都占据存储单元
- 是函数的通用性降低。在使用改函数功能的同时,还必须考虑到它所调用的函数外的全局变量。不易迁移
- 降低了程序的清晰性
注:全局变量与局部变量重名时,在局部变量范围内,会使用局部变量。
动态存储和静态存储(生存期)
-
静态存储
程序运行期间由系统分配固定的存储空间,程序运行的整个过程变量值都是存在的。
全局变量全部存放在静态存储区中。 -
动态存储
程序运行期间根据需要进行动态的分配存储空间,函数调用结束后才存储单元马上释放,函数值就不存在了。
形参、函数中的自动变量都存放在动态存储区中。
数据的存储类别
C语言中,每一个变量和函数都有两个属性:数据类型和数据的存储类别。数据类型即整型、浮点型等;数据的存储类别指数据在内存中存储的方式。
C的存储类别包括4种:自动的(auto)、静态的(static)、寄存器的(register)、外部的(extern)
-
自动变量(auto变量)
函数中的局部变量,若不专门声明为static(静态)存储类别,都是动态分配存储空间的。在调用该函数时,系统会自动分配存储单元,函数调用结束后就自动释放这些存储单元。因此这类局部变量被称为自动变量。自动变量的关键字auto是可以省略不写的。 -
静态变量(static变量)
- 局部变量
若希望局部变量的值在函数调用后依然保留,即不释放存储单位。可用关键字static进行声明,使其变为静态局部变量。
- 静态局部变量属于静态存储类别,函数调用后不释放存储单元
- 静态局部变量只赋初值一次,以后每次调用函数不在重新赋初值,而是保留上一次函数调用结束时的值。
- 虽然静态局部变量在函数调用结束后仍存在,但其他函数是不能引用它的。因为它是局部变量,作用域只局限于本函数。
- 全局变量
全局变量都是存放在静态存储区中的,因此它们的生存期是固定的。但全局变量的作用域是不固定的。一般来说,外部变量的作用域是从变量的定义处开始,到本程序文件的末尾。但通过关键字的定义可将变量的作用范围扩展。- 在一个文件内扩展外部变量的作用域(extern)
外部变量遵循先定义、后使用的原则。若想在定义之前就引用外部变量,则应在引用前用关键字extern对该变量作”外部变量声明“,将该外部变量的作用域扩展到此位置。 - 将外部变量的作用域扩展到其他文件(extern)
若程序包括多个文件,某两个文件想共同引用同一个外部变量,则可以:在任一文件中定义外部变量A,在另一文件中用关键字extern对该变量进行”外部变量声明“ - 将外部变量的作用域限制在本文件中(static)
若希望某些外部变量只能被本文件引用,则使用关键字static进行声明,称为”静态外部变量“
- 在一个文件内扩展外部变量的作用域(extern)
- 局部变量
-
寄存器变量(register变量)
一般情况下,变量(静态存储方式和动态存储方式)的值都是存放在内存中的。如果一些变量使用频繁,为提高执行效率,允许将局部变量的值放在CPU中的寄存器中。用关键字register声明,被称为寄存器变量
内部函数与外部函数
-
内部函数
该函数只能被本文件中的其他函数所调用,由关键字static声明,又称为静态函数
static 类型名 函数名(形参表); -
外部函数
该函数可供其他文件中的函数所调用,由关键字extern声明。函数本质上都是外部的,所以extern可以省写
**extern 类型名 函数名(形参表); **
例题汇总
例7.1初识函数
输出以下结果:
#include<stdio.h>
int main()
{
void print_star(); //函数的声明,声明函数的原型
void print_message();
print_star(); //函数的使用,使用print_star函数,输出*号
print_message(); //使用print_message函数,输出信息
print_star();
return 0;
}
void print_star() //函数的定义,定义函数功能
/*print_star函数的主要作用是输出*号*/
{
printf("********************\n");
}
void print_message()
/*print_message函数的主要作用是输出信息*/
{
printf("How do you do!\n");
}
例7.2找最大值
输入两个整数,要求输出其中值较大者。
#include<stdio.h>
int main()
{
int max(int x, int y); //函数声明,告诉编译系统max为有两个参数的函数
int a, b, c;
printf("请输入两个整数:\n");
scanf("%d%d", &a, &b);
c = max(a,b); //使用函数max比较两个数中的较大值
printf("最大值为:%d", c);
return 0;
}
int max(int x, int y) //定义max函数,max函数有两个参数,且有返回值,返回值为int整形
{
int z; //局部变量,临时分配存储空间
z = x>y ? x : y; //将x,y中的较大值,赋值给z
return z; //返回z的值,释放临时存储空间
}
例7.3返回值类型自动转换
同上,求最大值
#include<stdio.h>
int main()
{
int max(float x,float y);
float a, b;
float c;
printf("请输入两个数:\n");
scanf("%f%f", &a, &b);
c = max(a,b);
printf("最大值为:%f\n", c);
return 0;
}
int max(float x,float y) //max函数的参数为float浮点型,返回值为int整型
{
float z;
z = x>y ? x : y;
return z; //z虽为float浮点型,但max函数为int整型
} //所以z的值会由float转换为int,舍弃小数点后的数
运行结果为:
例7.4求和
求两个实数的和
#include<stdio.h>
int main()
{
float add(float x, float y); //声明函数,让编译程序知道函数的相关信息
float a, b, c;
printf("输入两个实数:\n");
printf(