引入
前面我们讲到为何要使用函数,以及为何要把功能封装到函数中,今天我们就来讲如何来定义和使用函数。
定义函数
为什么要定义函数呢?因为在 C 语言中,所用到的所有函数
,都必须先定义,后使用
。先要将函数的一些基本信息通知编译系统,这样在程序执行该函数时,编译系统才能按照预先指定的功能执行。
定义函数的四要素
定义函数需要包括一下几个内容:
- 指定
函数的名字
,用于在后期调用。 - 指定
函数的类型
,也就是函数返回值的类型
。 - 指定函数的
参数的名字和类型
,在后期调用时,向其传递数据,当然了,也可以没有参数
。 - 指定
函数的功能
,即函数需要做什么,对数据进行什么样的处理。这事最重要
的,也是函数体中的主要内容
。注意
对于 C 语言提供的库函数,是由编译系统事先定义好的,库文件包含了对各种函数的定义,我们不用再次定义,用#include
把他们有关的头文件
引入进来即可。
有关的头文件包括了对函数的定义声明,例如我们使用的stdio
.h、math.h
就包含了输入输出语句和数学函数等。
定义函数的方法
函数分为有参函数
和无参函数
,前面我们定义的输出星号和文字的函数就是无参函数。
定义无参函数
类型名 函数名 ( )
{
函数体
}
上面函数名后的括号中,为空,即没有参数。
也可以这样定义
类型名 函数名 ( viod )
{
函数体
}
函数名后的括号中,为void
,表示为空
,即函数没有参数。
注意
函数名前有类型名,这里的类型名指的是函数返回值的类型,即被调用函数返回给主调函数的值。这里可以写为void
,即空值,表示没有返回的函数值。
定义有参函数
我们通过一个返回两个数最大值的函数来看看如何定义一个有参函数,并且函数带有一个返回值。
1 | int max(int x,int y){ |
上面我们定义了一个自定义函数 max,功能是比较两个数的值,然后返回较大的那个数,我们根据定义函数的四要素来看看。
- 函数类型:
int max(...)
这里的 int 就是函数类型,也是函数返回值的类型,在这个例子中就是返回的最大值的类型。 - 函数名:
int max(...)
在 int 后面紧跟着的就是函数名,我们在调用时,也是通过这个函数名来进行调用。 - 参数名称和类型:
int max(int x , int y){...}
这里的 x 和 y 就是函数参数,x 和 y 前的 int 就是 max 的参数类型,我们在定义函数时,需要声明这些参数的类型。在给函数传递数据
时,我们也必须使用该类型的数据
。 - 函数功能:也就是函数花括号中,函数体中包含的内容。和 main 函数相同,我们需要对在函数中用到的
变量进行声明
,然后利用if...else...
判断处传递过来的 x 和 y 的大小,并把最大的传递给 big 变量,然后将 big 变量通过return
返回到主调函数中。
所以,定义有参函数的方法一般是:
类型名 函数名(参数类型名 参数名(即形参列表)
{
函数体
}
注意
函数体包含声明部分和语句部分!
定义空函数
有时候在程序设计中,也会用到空函数
类型名 函数名()
{ }
空函数最大的特点就是函数体是空的,即调用此函数时,什么也不做。
那么空函数有什么用呢?
空函数最大的作用就是占位,我们在编写一个较大的程序是,很多函数需要提前预留好,但是现阶段还没有办法编写好,所以先占位,等到程序后期在慢慢的优化、增加,起到锦上添花的效果。
调用函数
定义函数的目的就是为了调用它,并执行我们预先设定好的各种功能。
调用函数的形式
调用函数非常简单,前面我们也调用过了,一般形式是:
1 | star();//调用无参函数 |
调用无参函数
函数名();
调用有参函数
函数名(实参列表);
三种调用方法
根据函数的形式和位置的不同,可以有以下三种不同的调用方式:
函数调用语句
把函数调用单独作为一个语句,例如前面
1 | void star(){ |
这个 star 函数就是单纯的执行一个printf 语句
输出一行星星,没有参数也没有返回值,函数调用后即执行一些操作。
函数表达式
即函数的调用是出现在另一个表达式中的,也就是函数本身就是该表达式的一部分。这就要求函数要返回一个确定的值来参与运算,例如前面我们定义了一个 max(x,y) 的函数,返回最大值。那么:
1 | printf("将最大值放大两倍是:%d",2*max(x,y)); |
上面这行表达式,在 printf 语句中调用了 max 函数,并且函数的返回值还要进行乘法运算,然后运算结果返回给 printf 中。这就是函数本身出现在表达式中。
函数参数
即函数本身又是一个函数的参数,比如我们只有 max(a,b) 来求两个数的大小,但是现在有 a、b、c 三个数比大小,那么我们就可以把 max 函数的其中一个参数用 max 函数来代替,这里可能比较绕,我们举个例子。
1 | printf("三个数的最大值是:%d",max(a,max(b,c))); |
上面的这个 printf 语句,首先计算了 b 和 c 的大小,并将最大值返回,这个最大值又是外层 max 的参数,再进行一次比较,这样就算出了三个数的最大值。所以,函数也可以当做参数使用。
函数调用时的数据传递
主要讲函数的实际参数
和形式参数
的区别
,以及实际参数和形式参数的数据传递过程。
形式参数和实际参数
在调用有参函数
时,我主调函数和被调函数之间有数据传递的关系。我们称在定义函数时
函数名括号后的叫做形式参数(形参)
。在主调函数中调用函数时
,函数括号后面的叫做实际参数(实参)
。实际参数可以是常量、变量、表达式。
1 | int main(){ |
注意形参和实参
不是一回事,名称可以不同
。
实参和形参间的数据传递
在主调程序调用函数时,实参会传递给函数的形参一些数据,或者形参从实参获得了一些数据。调用到的这个值在函数调用期间有效,可以参与函数体内的运算。
我们称调用函数过程中发生的实参和形参的数据传递为虚实结合
。
我们来看一个具体的例子:
1 |
|
关于形参实参的数据类型不统一
如果形参和实参的数据类型不统一
,那么在执行函数时,形参会把实参转换为形参的数据类型
进行运算,然后返回。
关于形参和实参的传递方向
只能由实参传递给形参,实参和形参存储在不同的存储单元
,改变形参不会影响到实参,形参不能传递给实参
。
函数的返回值
我们希望调用一个函数,然后返回函数运行的结果,这个返回的结果就是返回值
。函数的返回值需要通过 return 语句返回到主调函数中,一般形式是:
return 返回值 或者 return (返回值)
包含多个返回值
一个语句中,可以包含一个或者多个返回值,即包含一个或者多个 return 语句,执行到哪个 return 哪个 return 就起作用。
返回值的类型
既然有返回值,这个值就一定要有一个数据类型,应该在定义函数的时候,就指定一个函数值的类型。一般的,我们在定义函数时的函数类型
应该和返回值的类型相同
。如果不同
,出现返回值类型与函数值类型不同的情况下,函数类型决定返回值的类型。
尾巴
这是我的个人学习笔记,主要是应付考研复习使用,充斥着一些吐槽和个人观点,并不严谨,欢迎大家参考、指正。