函数的概念
不同于数学上的函数,在C语言中,函数(function)就是一个完成某项特定任务的一段代码,所以函数也叫子程序。
函数的分类
库函数
为了提高写代码的效率,C语言的国际标准ANSI C规定了一些常用的函数的标准,被称为标准库。不同的编译器厂商根据ANSI提供的标准就给出了一系列函数的实现,这些函数被称为库函数。
各种编译器的标准库中提供了一系列的库函数,这些库函数根据功能的划分,都在不同的头文件中进行了声明。所以要使用不同的库函数就要包含不同的头文件。
库函数的使用方法:
C/C++官方的链接:https://zh.cppreference.com/w/c/header
自定义函数
语法形式:
ret_type fun_name(形式参数)//形式参数可以是0个、1个或多个
{
}
ret_type是函数的返回类型(有时函数的返回类型是void,代表什么都不返回)
fun_name是函数名
( )中的是函数的形式参数,( )中写void明确表明函数没有参数,也可以什么都不写
{ }括起来的是函数体。
函数调用
这里通过一个例子来说明:
写一个函数,用来完成两个整数的乘法操作
#include <stdio.h>
int Mul(int x, int y)
{
int r = 0;
r = x*y;
return r;
}
int main()
{
int a = 2;
int b = 7;
int c = Mul(a, b);
//函数Mul用来计算a与b相乘的结果,然后将结果赋值给变量c
return0 0;
}
这段代码中
int c = Mul(a, b);
就调用了函数Mul并将结果赋给了变量c。
其中a和b是真实传递给函数的参数,被称为实际参数,简称实参、而x和y是函数的形式参数,简称形参,形参是在函数被调⽤的过程中为了存放实参传递过来的值,而向内存申请了一块空间。
在函数调用过程中,虽然是把实参的值传递给了形参,但是这二者之间是相互独立的内存空间,可以说形参是实参的一份临时拷贝。
int Mul(int x, int y)
{
int r = 0;
r = x*y;
return r;
}
这个函数先把计算的结果放到变量r中,然后通过return语句来返回的,函数名Mul前面的int是该函数的返回类型,其与被返回的变量r的类型是一致的。
return语句
1:return后边可以是⼀个数值,也可以是⼀个表达式,如果是表达式则先执行表达式,再返回表达式的结果。
2:return后边也可以什么都没有,直接写 return; 这种写法适合函数返回类型是void的情况。
3:return返回的值和函数返回类型不⼀致,系统会自动将返回的值隐式转换为函数的返回类型。
4:return语句执行后,函数就彻底返回,后边的代码不再执行。
5:如果函数中存在if等分支的语句,则要保证每种情况下都有return返回,否则会出现编译错误。
6:函数不写返回类型时,编译器默认返回整型、如果函数要求返回值,但是函数中没有使用return语句返回值,那么返回的值是未知的。
函数传参的问题
注意事项
1:函数的形式参数要和函数的实参个数匹配
2:实参和形参的名字可以一样,也可以不一样
3:形参和实参的个数要匹配
4:函数在设计的时候要功能单一
数组作函数参数
1:数组在传参的时候,实参就写数组名,形参写成数组的形式
2:形参如果是⼀维数组,数组大小可以省略不写
3:形参如果是二维数组,行可以省略,但是列不能省略
4:数组传参,形参是不会创建新的数组的,形参操作的数组和实参的数组是同一个数组
函数的声明和定义
单个文件
不论是库函数还是自定义函数,函数在调用之前一定要先声明。这是因为编译器对源代码进行编译的时候是从第一行开始往下进行扫描的。
例如写一个代码求两个整数之和
#include <stdio.h>
int add(int x, int y)
{
int r = 0;
r = x + y;
return r;
}
int main()
{
int a = 8;
int b = 7;
int c = add(a, b);
printf("%d\n", c);
return 0;
}
这个代码中add函数的定义在上面,然后在下面的主函数中调用了add函数。函数的定义是⼀种特殊的声明,所以该函数的调用满足先声明后使用的原则。
#include <stdio.h>
int add(int x, int y);
int main()
{
int a = 8;
int b = 7;
int c = add(a, b);
printf("%d\n", c);
return 0;
}
int add(int x, int y)
{
int r = 0;
r = x + y;
return r;
}
这个代码中函数的定义在调用之后,所以在调用之前要先对add函数进行声明,即int add(int x, int y);要注意的是在函数的声明中,形参的名字可以省略,但类型不能省。
多个文件
一般在企业中我们写代码时候,代码可能比较多,不会将所有的代码都放在一个文件中;我们往往会根据程序的功能,将代码拆分放在多个文件中。 一般情况下,函数的声明、类型的声明放在头文件(.h)中,函数的实现是放在源文件(.c)文件中。
例如把上面求两个整数之和这个例子写成多个文件:
add.c文件中
int add(int x, int y)
{
int r = 0;
r = x + y;
return r;
}
add.h文件中
#include <stdio.h>
int add(int x, int y);
test.c文件中
#include "add.h"
int main()
{
int a = 8;
int b = 7;
int c = add(a, b);
printf("%d\n", c);
return 0;
}
这三个文件中add.c文件中是add函数的实现,add.h文件中是对add函数和printf函数的声明,test.c文件中要调用add函数和printf函数,所以要包含add.h的头文件,而包含我们自己写的头文件用""不用<>。
嵌套调用和链式访问
嵌套调用
嵌套调用就是函数之间的相互调用,写相对大型的程序离不开函数之间有效的互相调用。要注意的是函数是不能嵌套定义的。
链式访问
链式访问就是将一个函数的返回值作为另外一个函数的参数,像链条一样将函数串起来。