目录
一,函数
1,什么是函数
函数是完成特点任务的独立程序代码单元,不同的函数完成的操作也不一样。
2,为什么使用函数
使用函数可以避免编写一些重复性的代码
使程序更加模块化,从而提高程序代码的可读性,也方便后期修改。
二,简单函数
函数包含 返回类型,函数名和参数
1,创建函数
想要完成一项操作,比如说两个数相加,可以通过函数来完成:
int ADD(int,int) ; //声明
int main()
{
int a =10 ;
int b =20 ;
int c =ADD(a,b); //调用
printf("%d\n",c);
return 0;
}
int ADD(int a,int b) //函数
{
return a+b ;
}
- 函数和变量一样,有很多种类,在使用函数之前都要声明函数的类型,所以出了 int ADD(int,int) ; int 是函数的类型,表示返回值是int类型; ADD 表示函数名 ;(int,int)表示函数的参数是两个 int 类型的变量;结尾的分号说明这是在声明函数,不是定义;
- 如果这个函数出现在main() 函数之后,那么在main()函数里调用这个函数时需要声明,如果这个函数出现在main()函数之前,那么在main()函数里调用这个函数时可以不声明;在别的函数调用时也与之一样。
- 在main()函数里调用ADD函数,把变量ab的值传给 ADD(int ,int)函数中的两个int ,然后返回一个值给到c ,这时候c的值就是 a+b:
2,函数的类型
声明函数时必须声明函数的类型,带返回值的函数类型应该与返回值类型相同,没有返回值的函数为void类型。
特别要注意函数的类型是返回值的类型,不是函数参数的类型。
int sum(int a,int b) ;//函数声明
上述函数声明中,sum()函数的返回类型是int 为sum左边的int 。
3,函数的参数
函数分为库函数和自定义函数,库函数的参数可以通过一些工具查询,自定义函数的参数是由自己决定。比如说上述的ADD(int ,int )函数的两个int类型的参数是由自己定义的。我们根据函数是需要什么类型的参数去给函数传递值。
int ADD(int a,int b) //()内为参数类型,接受两个int类型的参数
{ //函数体
return a+b ; //返回值,返回一个int类型的结果
}
上述函数的定义,告诉编译器 ADD()使用两个参数,两个都是int 类型,这两个变量都被称为形式参数,简称形参。该参数是局部变量,也就是说离开这个函数之后就会被销毁,属于该函数私有,所以不会和别的函数中的同名变量产生冲突。
在定义函数参数时,应该注意每个变量都应该在其前声明类型,不然无效。
void add(int a,b,c) //无效的函数头
void add(int a,int b,int c) //有效的函数头
除去这种方式以外还有一种有效定义函数头的方式
void add(x,y,z)
int x,y,z ;
//这种方式也是有效的,不过不建议使用
三,函数的调用
调用函数时,应根据函数定义时需要的参数来传递参数,如果没有定义参数则不需要传参。
1,实际参数
函数调用时传递的参数,如上述的ADD()函数调用时,传递两个值,两个值之间用逗号隔开。
实际参数可以是常量、变量,或者时更复杂的表达式,不管用哪种方式,实际参数都要被求值,然后将值考贝给被调函数相应的形式参数。
注:如何区分实际参数和形式参数
形式参数时被调函数中的变量,实际参数时主调函数赋给被调函数的具体值。
2.传值与传址调用
2.1传值调用
把实际参数的值传给形参,实参和形参分别占有不同的内存空间,对形参的修改不会影响实 际参数。
2.2 传址调用
(1)是把函数外部创建变量的内存地址传递给函数参数的一种调用方式
(2)这种传递方式使函数内外部的变量联系起来(共用一块地址),也就是说函数内部对形 式参数的修改可以影响实际参数。
3.使用return
3.1 从函数中返回值
int add(int x,int y);//声明
int main()
{
int a =10,b=10 ;
int c = add(a,b) ;//调用,a,b为实际参数
//变量c接收从函数中返回的值
return 0;
}
int add(int x,int y) //函数定义,x,y为形式参数
{
return a+b ; //使用return 从函数中返回值
}
返回值可以是任意表达式的值,
return x>y?x:y ;
如果返回的类型与函数声明的类型不一样,如:
int div(int a,int b)
{
double z = a/b ;
return z; //返回类型与声明的类型不一样
// z会被强制类型转换为 int -> (int)z ,然后返回
}
3.2 终止函数
终止函数并把控制返回给主调函数的下一条语句。
int my_min(int a,int b)
{
if(a>b)
return b ;
else
return a;
}
在函数中使用多个return 语句也是没有错误的。
四,递归
简单来说递归就是函数自己调用自己
1.基本原理
使用一个演示:
void my_and (int n);
int main()
{
my_and (1);
return 0;
}
void my_and (int n)
{
printf(" 第 %d 级调用 地址是 %p\n", n, &n); // a语句
if (n < 4)
my_and(n + 1);
printf(" 第 %d 级调用 地址是 %p\n", n, &n);// b语句
}
1.1递归是如何工作的
- 函数首先接受了一个值 1作为初始值进入函数执行,所以a语句打印 第 1 级调用 然后打 印出地址。
- 因为1小于4 所以,进入if ,第 1 级调用实际参数为 n+1 (2),然后再次调用my_and()函 数(第2级),并把2传递给函数的n ,然后 a语句打印 第 2 级调用 然后打印地址。
- 因为2小于4所以,进入if,第2 级调用实际参数为 n+1 (3),然后再次调用my_and()函数(第 3级),并把 3传递给函数的n ,然后a语句打印出 第3级调用,然后打印地址。
- 因为3小于4 所以,进入if,第3级调用实际参数为 n+ 1( 4) ,然后再次调用my_and()函数(第 4级),并把4传递给函数的n,然后a语句打印出 第4级调用,然后打印地址。
- 因为 4 不小于4 ,所以不进入if ,函数不再调用自己,第4级接着执行 b语句打印 第4级,然后打印地址,然后返回 第3级 调用。
- 第3级调用继续执行后面的代码,也就是b语句打印,然后继续返回第2级调用,直到返回到最开始的 n=1 也就是第1 级调用时,执行完b语句打印之后函数结束。
我们通过观察每一级调用的地址可以看到 ,1-4与4-1的地址都是一样的,每级递归的n 都属于本级递归的,所以回到这一级时,使用同样的地址。
1.2 图解
每次调用都会返回一次,当函数执行完毕后,控制权会返回到上一级,必须逐级返回,不能跳级。
2.递归的一点总结
递归有有点也有缺点,优点是可以为某些编程问题提供了简单的解决方案,缺点是长的递归会快速消耗内存资源,不方便阅读和维护。
1,许多问题是以递归的形式进行解释,只是因为递归形式相较非递归形式更清晰
2,迭代方式的实现往往比递归实现效率更高
3,当一个问题相当复杂难以使用迭代解决时,不妨用递归实现,递归的简洁性便可以补偿它所 带来的运行时间的开销
总结
所有C函数都是平等的,每个函数都可以被自己或者其它函数调用,当然main()函数也可以被自己或者其他函数调用。