1.函数的概念
函数是一个大型程序的某部分代码,由一个或多个语句块组成,负责完成一些特定任务,具备独立性,提供封装的细节和隐藏
2.库函数
库函数是C语言库本身具有的函数,你只需要引入头文件调用就行了
比如我们常用的 printf() 函数,它就是一个典型的库函数, 是由C语言本身提供的,但我们在使用printf()函数前,需要先引入 stdio.h的头文件才能使用。
类似于 printf()的库函数还有很多,还有scanf(), strlen()…
3.如何自定义函数
**库函数可以方便我们做一些常规操作,但是一个程序里的很多操作,需要我们自己来完成。 这样就需要用到函数,那么函数如何定义呢? 很简单,函数的定义格式是 返回类型 函数名(参数列表) {函数体} 先来看看一个没有参数,也没返回类型的简单函数 **
void Printf()
{
printf("hehe\n");
}
如果参数 没有返回值,那么 返回类型就要写void,如果有返回值,那么返回值类型就写返回参数的类型,例如
函数的返回值 类型 与返回参数的类型要一致
4.函数的调用
那么,我们有了一个函数后,应该怎么使用这个函数的呢? 函数的调用格式是 函数名(参数列表); 没参数的情况下就是 函数名(); 调用代码如下
#include<stdio.h> //头文件
// 这是一个自定义函数
void Printf()
{
printf("hehe\n");
}
//main 函数
int main()
{
Printf(); // 调用自定义函数 函数名();
return 0;
}
如果函数是有参数的情况下, 函数调用时 需要传入参数
void Printf2(int a, int b)
{
printf("%d %d\n",a,b);
}
int main()
{
int a = 10;
int b = 10;
Printf2(a,b); //调用时 需要 传入对应的参数列表
return 0;
}
5.函数的参数及返回值
5.1 形参
函数接收参数时会重新开辟一块空间,并把传入的数的值赋给这块空。就是函数重新定义了一个变量,并把传入的值赋值给这些变量,这些变量就是形参,形参在函数结束后会自行销毁。
形参是该函数独有的,函数结束,这些形参也会消失。形参的作用域只限于它所在的函数
5.2 实参
函数接收的参数 叫形参,那我们调用函数时传入的参数,就叫实参
形参的改变不会影响实参!!!形参有单独的内存空间,在函数结束后形参就会被销毁
5.3 函数的返回值
当一个函数的返回类型 不是 void的时候,就说明函数是有返回值的,函数的返回值可以被接收。很多时候我们在函数实现了一些功能之后,都希望函数返回给我们一些被操作的值。比如我要用函数实现两个数相加,那么这个函数最好可以返回2个数的和。
int add(a,b)
{
int c = a + b;
return c; //返回值c
}
int main()
{
int a = 10;
int b = 10;
int sum = add(a,b); // 接收返回值
printf("%d",sum);
return 0;
}
那让我们来看看运行结果是不是20
6.函数递归
递归是函数里面一个很复杂的内容,也是很重要的内容,很多初学者都被递归折磨的不轻。那么我们就来讲讲递归。
程序调用自身的编程技巧,就叫递归。 简单来说,就是一个函数它自己调用自己,这就叫递归。 我们先来看看世界上最简单的递归
int main()
{
printf("hello\n");
main(); //在函数里面调用本身
return 0;
}
我们可以看到 main 函数里面 有一段 main(); 代码,就是调用自己,那我们看看最后结果
调用到一定程度时,报了个错误,栈溢出了,这是因为 函数只有在执行完毕后才会销毁,但是 main 函数一直调用自身,函数堆积 一直没有销毁,所以就造成了栈溢出。面对这种情况,我必须给递归加上一个限制条件,防止栈溢出。先让我们来看一段代码
void Printf(int num)
{
//递归的限制条件,个位数 小于 9 后结束递推
if (num > 9) //递归限制条件
Printf(num/10); //递归 条件变化
printf("%d ",num%10); //打印个位数
}
int main()
{
int num = 0; //要打印的数
scanf("%d",&num);
Printf(num); //函数无返回值,参数 num
return 0;
}
这段代码的功能是输入一个数,并依次 打印 每位数,运用到了递归的方法。那么我们怎么理解这个代码呢? 假设我们输入一个数字 2022
我们输入的值是2022,先把2022 传了进去, 进入到了 if条件,满足条件后,又调用了自身,传值是 2022/10
第二次里面就变成 202 ,然后又调用自身,传的值是 202/10,也就是 20
num = 20 后依旧满足if 条件,继续调用自身
现在 num的值=2了,不满足自身,所以打印 num%10的值,也就是2%10,此时打印了2,打印结束之后这个函数已经结束了,所以会返回到上一个函数执行上一个函数未执行的内容
此时函数依次回归,执行以下代码,函数3的 num 参数是20,所以 20%10= 0,所以函数 3会打印 0
函数2 打印 202%10,也就是2
函数1执行完,该函数就执行完毕,我们可以发现,函数1是最后才执行完的,因为函数递归了3次,所以给函数分了个编号,方便理解。所以函数的的打印顺序是 4-3-2-1,函数4打印 2,函数3打印0,函数2打印2,函数1 也打印2,所以最后的打印结果是 2 0 2 2
再使用递归时,我们必须要注意两点事项,否则会出栈溢出导致程序崩溃。在使用递归时,我们必须要明确两点
1. 递归的限制条件,当满足条件时,递归不再继续
2. 条件的变化,每次递归后都必须让递归条件更满足限制条件
现在我们就来看看几段递归代码的限制条件,和条件变化
代码1
void Printf(int num)
{
if (num > 9) //限制条件,如果 num<9,那么递归就不再继续
Printf(num / 10); //每次递归,num都会/10,每次递归后num越来越接近上面的限制条件
printf("%d ", num % 10);
}
int main()
{
int num = 0; //要打印的数
scanf("%d",&num);
Printf(num); //函数无返回值,参数 num
return 0;
代码2
int power(int n,int k)
{
if (k != 0) //递归限制条件,如果k =0,结束递归
{
k--; //递归条件变化,每次递归后,k都会-1,最后会满足限制条件
return n * power(n, k);
}
else
return 1;
}
int main()
{
int n = 0; //n
int k = 0; // k 次方
scanf("%d %d",&n,&k); // 分别输入 n 和 k 次方
int ret = power(n,k);
printf("%d 的 %d 次方 : %d",n,k,ret);
return 0;
代码3
int digit_sum(int num)
{
//递归限制条件,就是 num < 9,就不再递归
if (num < 9)
return num; //如果满足限制条件
else
return num % 10 + digit_sum(num / 10); //反之num>9 继续递归,每次递归 num 都会 /10 ,每次递归都逐渐满足限制条件
}
int main()
{
int num = 0; //被操作的值
scanf("%d",&num);
int sum = digit_sum(num); // 接收返回值
printf("%d",sum);
return 0;
}
代码 4
int my_strlen(char * c) // 用一个指针来接收地址
{
//1.递归的限制条件
if (*c != '\0') // 递归的限制条件,指针解引用后不=\0,如果 是\0,不再递归
return 1 + my_strlen(c+1);//每次递归,指针都会往后挪移格,逐渐满足*c等于\0的条件
else
return 0; // 走到 \0了,返回0结束递推,开始回归
}
int main()
{
char arr[]= "hello bit";//定义一个字符串
int len = my_strlen(arr); //数组名是 首元素地址,所以传进去的是 h 的地址
printf("%d",len);
return 0;
}
以上代码均来自本人git
感谢大家支持!