不知不觉,小刘已经讲了十一天C语言了,语法、数据结构、数组、结构体、指针的概念和使用大家都已经了然于心,但是想用C语言开发一个有用的程序还需要一个很关键的部分,那就是编写“函数”。
“函数这个名字大家肯定都不陌生,数学中很常见。例如f(x)=x+1,这就是一个函数的表达式。其中f称为映射法则,它可以用很多其他符号来表示,括号中的x是函数的一个参数,或者叫自变量,通过等号右边的式子,对参量进行运算,最终得到的值就是通过函数想要最终得到的结果。C语言中的函数也可以从数学中的函数进行类别。”
“首先C语言中函数的定义如下:”
函数类型 函数名(形式参数){
函数体;
return 返回值(与函数的类型一致);
}
“其中函数类型和函数返回值的类型是一致的,形式参数是在函数体中才有效的,函数外则无效,通常我们想要拿一个变量到函数中进行运算,那么我们在调用函数的时候,将实际参数的位置放到与形式参数对应的位置即可,如果你的函数不需要传入其他的参数,在定义时括号中也可以什么都不写。”
“下面我们通过一个例子来体验一下函数的作用:”
#include<stdio.h>
int main(){
int a=1;
printf("a=%d",a);
return 0;
}
输出:
“有的同学可能会有疑问,这也没定义函数啊,函数在哪呢?”
“我给大家看一张图大家就明白了:”
C语言项目组织方式 :
[图片来源:](C语言中文网:C语言程序设计门户网站(入门教程、编程软件))
“其实一个C语言的项目就是由一个个文件构成的,源文件里面装的就是源代码,那么项目的功能是怎么通过代码实现的呢,答案就是:通过函数实现功能。C语言项目的主要工作就是写函数。”
“其中main()也是函数,只不过他是一个比较特殊的函数,人称:主函数。主函数就是程序的起点,所有其他函数必须在主函数中才能实现调用。当然,我们初学时写的程序功能比较简单而且是一次性的结果(无需重复使用该功能),就可以直接写在主函数中去实现。如果我们想要求一个比较复杂的问题并且此功能还要去重复使用,那么我们通常定义一个函数来解决。如:求1~n的和用函数的方法来实现:”
code_1:void类型
#include<stdio.h>
void sum(int n){
int sum=0;
for(int i=1;i<=n;i++){
sum+=i;
}
printf("%d\n",sum);
}
int main(){
int n=0;
scanf("%d",&n);
sum(n);
return 0;
}
code_2:int类型
#include<stdio.h>
int sum(int n){
int sum=0;
for(int i=1;i<=n;i++){
sum+=i;
}
return sum;
}
int main(){
int n=0;
scanf("%d",&n);
printf("%d",sum(n));
return 0;
}
code_3:无参型
#include<stdio.h>
int sum(){
int n=0;
scanf("%d",&n);
int sum=0;
for(int i=1;i<=n;i++){
sum+=i;
}
return sum;
}
int main(){
printf("%d",sum());
return 0;
}
“上面三种就是函数定义和调用的实例,可以发现这些函数都是写在主函数main上面的,如果把函数写在主函数下面可不可以呢?”
“如果我们把函数直接写在main函数的下面会发生报错,说没有找到“sum”函数,那该怎么办呢?不用急,我们只要在主函数上面或者里面对函数声明一下,就可以了。”
函数声明语法:
函数类型 函数名(形式参数<无参即不用填>);
如:
或:
“C语言中函数的定义都是相互独立的,就是不能在一个函数中定义另一个函数,在语法上是不允许的,如:”
“函数的调用除了在main函数中使用以外,还可以在其他函数中使用或者在自身函数中使用。其他函数中相互使用时函数的调用的函数必须是先声明或者先写好的,否则语法不会通过。函数调用自身还有一种说法叫“递归”,下面我们就来了解一下递归。”
#include<stdio.h>
void print(int n){
printf("%d,",n);
if(n!=0){
return print(--n);
}
}
int main(){
int n;
scanf("%d",&n);
print(n);
return 0;
}
“上面的例子中print函数重复调用了多次,就是一种递归:”
“递归虽然是一种巧妙的函数调用方式,但是也有巨大的问题,那就是空间或者时间开销很大:”
空间:
递归函数内部嵌套了对自身的调用,除非等到最内层的函数调用结束,否则外层的所有函数都不会调用结束。通俗地讲,外层函数被卡主了,它要等待所有的内层函数调用完成后,它自己才能调用完成。
时间:
每次调用函数都会在栈上分配内存,函数调用结束后再释放这一部分内存,内存的分配和释放都是需要时间的。
每次调用函数还会多次修改寄存器的值,函数调用结束后还需要找到上层函数的位置再继续执行,这也是需要时间的。
所有的这些时间加在一起是非常恐怖的。
“因此,掌握了递归的同时,更重要的是如何使用递归。”