一.函数介绍
1.为什么需要函数:
①解决了重复代码的问题
②有利于程序的模块化
2.概念:
逻辑上:能完成特定功能的独立代码块叫函数,可以看成1个黑匣子
形式上:能接收数据,能对接收的数据进行处理,能将处理数据得到的结果返回(也有可能不包含某几项)
函数是C语言中的基本单位,类是C++/Java/C#中的基本单位
3.函数的分类
(1)有参函数和无参函数:
参数传入错误(数据类型不同,传入的参数过多/少)会报错
//有参函数:
<type> <func>([<type1> <param1>...]) {
<command1>;
...
[return <re>;]
}
//无参函数:
<type> <func>() {
<command1>;
...
[return <re>;]
}
(2)有返回值函数和无返回值函数:
//有返回值函数:
<type> <func>([<type1> <param1>...]) {
<command1>;
...
[return <re>;]//type和re的数据类型冲突时,以type为准
}
//无返回值函数:
void <func>([<type1> <param1>...]) {
<command1>;
...
}
//或:
void <func>([<type1> <param1>...]) {
<command1>;
...
return;
}
(3)库函数和自定义函数:
库函数:由C语言的标准库提供
自定义函数:由用户自行编写
(4)值传递函数和地址传递函数:
值传递函数:
地址传递函数:
(5)主函数和普通函数:
main()函数的返回值参见:https://blog.csdn.net/z_ryan/article/details/80979008
//主函数:即main()
//1个C语言编写的程序,一定从main()开始(但不一定从main()结束)
//1个程序,必须有且只有1个主函数
int main([<param1>...]) {
<command1>;
...
[return <re>;]
}
//如果不加return语句,默认返回0;在某些编译器中,返回值是void也可以
//如果不指定返回值的类型,则相当于int main() {...}
//re用于说明程序的退出状态:返回0代表程序正常退出;返回其它数字的含义由系统决定,通常代表程序异常退出
//普通函数:其他所有函数
二.函数的语法
1.如何定义1个函数:
<type> <func>([<type1> <param1>,<type2> <param2>...]) {
<command1>;
...
[return <re>;]
}
//return会终止函数并返回指定的值,在C语言中,是1种跳转语句
//如果只有return没有re,则只终止函数,不返回任何值
//参数说明:
type:指定函数返回值的数据类型(void表示无返回值)
//函数的返回值的数据类型也称为函数的类型
//type和re的数据类型冲突时,以type为准
func:指定函数名
type1 param1...:指定要求传入的参数(形参)及其类型
//可以在这里定义形参变量,不需要提前定义
//void表示不传入任何参数(需要单独使用)
//每次执行完函数.为param分配的内存空间都会被释放;但多次调用系统函数,分配给同1个参数的内存空间可能不同
//这里定义了变量在函数内部的变量名
command:指定函数要执行的命令
re:指定返回值;默认返回0
//实例:
void max(int i,int j) {
if (i>j) {
printf("%d\n",i);
} else {
printf("%d\n",j);
}
}
2.如何调用函数:
[<re>=]<func>([<param1>,<param2>...]);
//会执行指定函数中的命令
//参数说明:
func:要执行的函数的函数名
param:传入的参数(实参)
//可以是值,也可以是另1个变量
re:用于接收返回值的变量
形参与实参:在函数内部,形参是变量名,而变量的值由对应的实参决定
二者的个数必须相同,位置一一对应,数据类型必须兼容
主调函数与被调函数:如果在f1()中调用f2()
则称f1()为主调函数,f2()为被调函数
//实例:
#include <stdio.h>
int max(int i,int j) {//也可以定义在main()内部
if (i>j) {
printf("%d\n",i);//结果:[未执行]
} else {
printf("%d\n",j);//结果:5
}
return 1
printf("AAA");//结果:[未执行]
}
int main(void) {
int a=3,b=5;
int r=max(a,b);
printf("%d\n",r);//结果:1
return 0;
}
//函数内部还可以再调用函数:
#include <stdio.h>
int main(void) {
void qqq(boid) {
printf("CCC\n");//结果:CCC
}
int ppp(void) {
printf("BBB\n");//结果:BBB
qqq();
}
printf("AAA\n");//结果:AAA
ppp();
return 0;
}
#include <stdio.h>
int main(void) {
int ppp(void) {
printf("BBB\n");
main();//结果:[成功]
}
printf("AAA\n");
ppp();
return 0;
}
#include <stdio.h>
int main(void) {
printf("AAA\n");//结果:[成功]
main();
return 0;
}
3.函数前置声明(函数原型)
(1)功能:
①告知编译器之后可能出现的某变量代表1个函数
②告知编译器该函数的形参和返回值的信息
C90中增加,旧式编译器可能无法识别
(2)自定义函数的声明:
参见:https://www.zhihu.com/question/35890756?sort=created
如果函数调用在函数声明的前面,则必须有该函数的前置声明
//实际上在某些编译器/某些标准中,如果该函数的返回值是int/void,可以不用进行前置声明
如果函数调用在函数声明的后面,可以不加该函数的前置声明
//语法:
<type> <func>([<type1> <param1>...]);
//在ANSI C之前的标准中可以省略参数,如[int f(int a);]也可写成[int f();];但从ANSI C开始,不再接受接受这种写法
//如果不声明type,旧标准会假定其为int,但C99不支持这种假定
//参数名可以省略,只指定参数的数据类型
//参数说明:同二.1
//实例:
#include <stdio.h>
//float rq(void);//rq()的声明也可以在这里
int main(void) {
//float rq(void);//rq()的声明不可以在这里或main()中的任何位置,因为这不在调用函数的作用域中
printf("AAA\n");
printf("%d\n",ppp());
return 0;
}
int ppp(void) {
float rq(void);//声明//也可写成[float rq();]
short i=1;
if (1) {
float cc=rq();
//float rq(void);//rq()的声明也不能在这里,因为这时rq()已被调用
return 1;
} else {
return 0;
}
}
float rq(void) {
printf("AASSDD\n");
}
(3)对库函数的声明:
#include <<filename>.h>//结尾不需要分号(;)
//相当于把<filename>.h中的内容都复制到该命令所在的位置
//参数说明:
filename:指定库函数所在的头文件的文件基本名
//实例:
#include <stdio.h>//printf(),scanf()都在该库文件中
(4)注意事项:
①函数的前置声明是1个语句,结尾必须加分号(;)
②前置声明中函数的参数类型/返回值类型必须和函数定义中的相同
③ANSI C允许前置声明中的参数名和函数定义中的不同,但实际使用的应是函数定义中的变量名
④声明的位置必须满足: ①在main()前面或该函数被调用时所在的作用域中 ②在该函数被调用的位置之前
三.常用库函数
参见 C语言基础.库函数 部分
四.递归
参见 C语言基础.递归 部分
即函数调用自身
相关: ①栈,压栈,出栈 ②函数如何调用另1个函数