函数初阶
点击此处可以查看一些简单的题目[自定义函数和递归函数题目]
(https://blog.youkuaiyun.com/wang_yiduo/article/details/87201683)
函数的定义
- 在维基百科中对函数的定义是它是一个程序中的子程序,是一个大型程序中的部分代码,由一个或者多个语块组成它负责完成某项特定的任务,而且相较于其他代码具有相对的独立性
库函数
- 为了提高程序的效率和可移植性,所以很多的编程语言都会提供一系列的库函数从而方便程序员的使用,比如说printf,它就是一个非常常用的库函数,每次在使用的它的时候我们就只需要加它的头文件即可,不需要自己去实现这个函数的具体功能,基础库已经帮你实现好了,你可以直接拿来使用,无疑是提高了我们编程的效率
C语言的库函数:
- IO函数(文件的输入输出函数)
- 字符串操作函数
- 字符操作函数
- 内存操作函数
- 时间/日期函数
- 数学函数
- 其他库函数
库函数举例:
-
fwrite(IO函数)
size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );
作用:给文件中写内容 -
strcpy(字符串操作函数)
char * strcpy ( char * destination , const char * source );
作用:拷贝字符串 -
puts(字符操作函数)
int puts ( const char * str );
作用:标准输出一个字符 -
malloc(内存操作函数)
void * malloc ( size_t size );
作用:动态内存申请 -
time(时间/日期函数)
time_t time ( time_t * timer );
作用:获取当前时间 -
pow(数学函数)
double pow ( double base, double exponent );
作用:进行指数运算
库函数具体是怎样实现的可以去看我的字符串函数的博客
库函数的组成:
以pow函数为例
double指的是函数返回值的类型
pow指的是函数名
()里面的是函数的参数
注意:
- 在使用这些库函数的时候必须要加上包含#include对应的头文件
- 库函数对我们程序员来说是非常重要的,但是C语言的库函数太少了,在更的情况下我们还是在使用自定义函数
自定义函数
-自定义函数和库函数一样,由函数名,返回值类型和函数参数,但是不一样的是自定义函数是自己设计的,这就给了我们很大的发挥空间
自定义函数组成:
ret_type fun_name ( paral , * )
{
statement;//语句项
}
1:ret_type 返回值类型
2:fun_name 函数名
3.parallel 函数参数
代码演示:
//找出两个数之间的较大的那个数
#include<stdio.h>
int Max(int x,int y)
{
return x>y?x:y;
}
int main()
{
int a=1;
int b=2;
int max=Max(a,b);
printf("max=%d\n",max);
return 0;
}
结果:max=2
函数的参数:
-
实际参数:
真实传给函数的参数,可以是:常量,变量,表达式等等,但是无论实参是何种类型的量,在进行调用的时候,它们都必须要有确定的值,以便把这些值传给形参
-
形式参数:
指的是函数名后面括号中的变量,因为形式参数只有当函数被调用的时候才会使用,而一旦函数调用完后便会销毁,因此形参只在函数中有效
注意:形参是实参的拷贝,无论形参怎么变都不会影响实参
代码演示://交换两个整形变量的内容 #include<stdio.h> void Swap(int x,int y)//这里的x,y就是形式参数 { int tmp=x; x=y; y=tmp; } int main() { int a=1; int b=2; Swap(a,b);//这里的a和b就是实际参数 printf("a=%d,b=%d\n",a,b); return 0; }
结果:a=1,b=2
原因:虽然在调用函数的时候我们确实交换了1和2但是这里交换的是实参传给形参的1和2这两个数字,并不是a和b这两个变量,而这种操作被叫做传值调用,想要解决这类问题必须要进行传址调用
函数的调用:
-
传值调用
函数的形参和实参分别占有不同的内存空间,对形参进行修改不会影响实参
-
传址调用:
将函数实参的地址传给形参的一种调用方式
这种传参方式可以让实参和形参之间建立联系,也就是可以从函数内部直接操作函数外部的变量代码演示:
//交换两个整形变量的内容 #include<stdio.h> void Swap(int* x,int* y) { int tmp=*x; *x=*y; *y=tmp; } int main() { int a=1; int b=2; Swap(&a,&b);//这里传的是实参的地址 printf("a=%d,b=%d\n",a,b); return 0; }
结果:a=2,b=1
注意:为什么传值和传址会有这样的区别,在这里不在加以叙述,大家可以去看我的栈帧—函数高阶这篇博客
函数递归:
函数递归的定义:函数自身调用自身的一种技巧,通常是讲一个大型复杂的问题层层转换为一个与原问题相似的规模较小的问题来求解,递归的策略只需要少量的成俗就可以描述出解题过程所需要的多次重复计算,大大的减小了程序的代码量.思考方式在于:大事化小
函数递归的必要条件:
- 存在限制条件,当满足这个条件的时候停止递归
- 每调用一次都要比上一次更接近限制条件,不能无限递归,否则没有任何意义
代码演示:
//求第n个斐波那契数(不考虑溢出)
#include<stdio.h>
int Fib(int x)
{
if ( x <= 2)
return 1;
else
return Fib(x-1)+Fib(x-2);
}
int main()
{
int n=5;
int fib=Fib(n);
printf("fib=%d\n",fib);
return 0;
}
结果:fib=5
原因:斐波那契是的特点某个数是它前两个数之和,第一个数和第二个数都为1,现在求第五个数,因为第五个数等于第四个数和第三个数的和,而第四个数的和又等于第三个数和第二个数的和,第三个数等于第二个数和第一个数的和可以看出来它们每次计算的方式是相同的,可以用递归来解决,因为前两个数都为1,所以当x<=2时那它就是1,用这个来做限制条件,而>=序号为2的数字则可以继续调用自己一直到它<=序号为2的数字为止
注意:递归比较复杂需要练习大量的题目,有兴趣的可以做做我这篇博客的演示题目,里面就有一些比较好的递归题目