C语言:函数
1.引言:
在C语言编程中,函数是不可或缺的,有了函数,所以我们的编程变得更加简便,不需要像过去的人一样,每写一次代码都需要临时写一大段代码达到打印的目的,过去的人们意识到这大幅度影响到了写代码的效率,所以,便有了今天经典的库函数,也渐渐为编程引入了函数的概念
2.函数的种类
在C语言中,函数分为了两大种:
- 库函数
- 自定义函数
库函数,顾名思义,就是引用了库中的函数
而自定义函数也很好理解,就是自己临时写了一个函数,后面想用这个函数便可以直接引用,而不需要引用库中的函数,这也奠定了其在编程中的重要地位
3.库函数
在库函数使用前,我们必须得做一件事情,那便是引用其相应的头文件,就像最经典的
#include<stdio.h>
这就是输入输出的标准函数:standard input output
在我们写代码的过程,其几乎是必不可少的一部分,没有了它,我们连基本的输入输出都很难做到,因为这需要我们临时写一段输入输出的代码
假如不引用编译器就会报错:
未定义标识符XXXX
这就相当于一个路人连工具箱都没见过,就让他直接去使用工具箱内的道具,这显然不合理,所以至少得让他摸到工具箱,然后才能使用其中的工具
这就是我们在使用库函数时,必须得先引用其相应的头文件,这就能使编译器能辨别出你的想法,才能完成你给予编译器的任务
除此之外还有
#include<string.h>
#include<Windows.h>
#include<math.h>
......
有兴趣的可以去像MSDN之类的网站查一查有哪些库函数,和其包括的头文件,这里就不再一一赘述了
4.自定义函数
自定义函数在我们日常编译中发挥着巨大作用,它可以提高我们的写代码的效率,例如:当我们在反复需要一个功能时,便可以通过写一个函数来实现这功能,当下面还需要用到该功能时,直接引用函数即可,不需要又重新的去写这一段代码
例如:
这里需要我们通过一个函数来实现判断某一年是否为闰年
#include <stdio.h>
void leapYear(int x)
{
if((x%4==0&&x%100!=0)||(x%400==0))
{
printf("%d是闰年\n",x);
}
}
int main()
{
int year=0;
scanf("%d",&year);
leapYear(year);
return 0;
}
或是通过一个函数来判断一个数是否为质数
#include <stdio.h>
#include <math.h>
int isPrime(int x)
{
if (x == 1)
{
return 0;
}
if (x == 2||x==3)
{
return 1;
}
for (int i = 2; i <= sqrt(x); i++)
{
if (x % i == 0)
{
return 0;
}
}
return 1;
}
int main()
{
int num = 0;
scanf("%d", &num);
if (isPrime(num))
{
printf("%d是质数\n",num);
return 0;
}
else
printf("%d不是质数\n",num);
return 0;
}
5.函数的嵌套
函数在使用中存在着嵌套使用
即:
#include <stdio.h>
#include <math.h>
int isPrime(int x)
{
if (x == 1)
{
return 0;
}
if (x == 2||x==3)
{
return 1;
}
for (int i = 2; i <= sqrt(x); i++)
{
if (x % i == 0)
{
return 0;
}
}
return 1;
}
void leapYear(int x)
{
if(isPrime(x))//判断一年是否为质数和闰年
{
if((x%4==0&&x%100!=0)||(x%400==0))
{
printf("%d是闰年\n",x);
}
}
}
上面的例子就是一个简单的函数嵌套,但是函数不能嵌套定义,例如:
#include <stdio.h>
#include <math.h>
int isPrime(int x)
{
void leapYear(int y)
{
if((y%4==0&&y%100!=0)||(y%400==0))
{
printf("%d是闰年\n",y);
}
}
if (x == 1)
{
return 0;
}
if (x == 2||x==3)
{
return 1;
}
for (int i = 2; i <= sqrt(x); i++)
{
if (x % i == 0)
{
return 0;
}
}
return 1;
}
上面这种就是所谓的嵌套定义,但这是一种错误的写法,函数是不允许嵌套定义的
6.函数的链式访问
函数还可以进行链式访问,例如:
#include <stdio.h>
int main()
{
printf("%d",printf("%d",return 34);
return 0;
}
这就是一个经典的链式访问,打印结果是:1234,至于为什么?
原因是printf打印的是return返回的字符数量,所以第2个printf输出的是2,因为第2个printf打印的字符是1个,所以第1个printf打印的是1
因此最终结果是1234
7.函数的声明
对于函数的使用通常需要进行声明
例如:
int isPrime(int x);//这就是函数的声明
int isPrime(int x)
{
if (x == 1)
{
return 0;
}
if (x == 2||x==3)
{
return 1;
}
for (int i = 2; i <= sqrt(x); i++)
{
if (x % i == 0)
{
return 0;
}
}
return 1;
}
当然正常的函数声明会放在头文件中
就像
这就是将声明放在头文件中,之后想便可以直接引用源文件中的isPrime函数了
8.函数的递归与迭代
函数的递归
函数的递归顾名思义就是将一个函数有放进本身的这个函数,简单来说就是重复使用一个函数直到满足限制条件
例如:
输入一个字符串,并模拟strlen将其长度打印出来
#include <stdio.h>
int Count(char* x)
{
if (*x != '\0')
return 1 + Count(x + 1);
else
return 0;
}
int main()
{
char arr[] = "abcdef";
int count = Count(arr);
printf("%d\n", count);
return 0;
}
这个例子中就可以使用了递归
在此我得先传递一下递归思想:递归思想就是将一件麻烦的事,逐渐逐渐地转化为一件重复的简单事情,像这里我们知道当字符串遇到\0时就会停止,所以我们可以将第1个字符看作是1,并将后面所有的部分看作是(x),以此类推,直到碰见\0,然后结束整个过程
再看一个例子:
输入一串数字,并将其依次打印出来(而非一次性打印出来)
#include <stdio.h>
void read(int x)
{
if (x > 9)//大于9说明还不是个位数,也同时增添了限制条件
{
read(x / 10);//可以每次减少末尾的1个数字,也同时在接近限制条件
}
printf("%d ", x%10);//x%10可以得到个位数字
}
int main()
{
int x = 0;
scanf("%d", &x);
read(x);
return 0;
}
这个例子就很好地解释了何为递归
从上面的例子中我们都看见了使用递归时必须要有限制条件,且随着递归的进行,离限制条件越来越近,假如缺少其中1个那都形成了死递归,最终导致程序崩溃
在此我还得补充一点,那就是当使用函数时,函数中会存在形参,而形参就是实参的一份临时拷贝,每当使用一次函数,形参会向内存中的栈区申请一定内存,而内存总是有限的,因为死递归,导致形参一直向栈区申请内存,当形参申请的内存过多时,就会出现栈溢出的现象,也是导致程序崩溃的原因,这就是为什么需要上面的限制条件和随着递归的进行,离限制条件越来越近
函数的迭代
函数的迭代就是函数中的值随着循环逐渐改变,它在有些地方可以使函数的效率加快
例如:
写出斐波那契数列
#include <stdio.h>
int Fib(int x)
{
if (x < 3)
{
return 1;
}
else
{
return Fib(x - 1) + Fib(x - 2);
}
}
int main()
{
int num = 0;
scanf("%d", &num);
int ret = Fib(num);
printf("%d\n", ret);
return 0;
}
通过递归的形式,我们发现也可以做到,但随着数字输入的增加,我们发现,其打印的效率肉眼可见的在降低,通过调试发现,每当其返回一次,它就会向前重新计算一次,而不会将固有值记录下来,这就是其效率低的主要原因
这时候就可以使用迭代,因为迭代会记录下每一次运行的值,在这方面,可以提高函数的效率
#include <stdio.h>
int Fib(int x)
{
int x1 = 1;
int x2 = 1;
int tmp = 1;
while (x > 2)
{
tmp = x1 + x2;
x1 = x2;
x2 = tmp;
x--;
}
return tmp;
}
int main()
{
int num = 0;
scanf("%d", &num);
int ret = Fib(num);
printf("%d\n", ret);
return 0;
}
最终通过几次测试,随着输入的数字增大,其效率远远超过使用递归的方法
总结
函数在我们的编程中起着至关重要的作用,特别是自定义函数,以及函数的递归与迭代