什么是函数在数学中其实函数这个概念在小学中我们就能够了解到函数这个概念了。比如y kxb这个一次函数有自变量和因变量。在C语言中也引入了函数Function这个概念。也被有些人称为子程序。C语言中函数就是完成一些特定功能或者任务的一小段代码。在一般情况下我们会见到两种类型的函数。库函数和自定义函数。库函数C语言中本身是不提供库函数的。C语⾔的国际标准ANSI C规定了⼀ 些常⽤的函数的标准被称为标准库不同的编译器⼚商根据ANSI提供的C语⾔标准给出函数的实现。这些函数就被称为库函数。有了库函数一些常见的功能就不需要程序员自己去实现了一定程度提升了程序员的开发效率。比如我们在数学中使用的平方根sqrt#includestdio.h #includemath.h int main() { double x 4; double y sqrt(x); printf(%lf\n,y); return 0; } 结果如下自定义函数 类型函数名字(形式参数) { 里面是函数体 }我们可以将函数想象成一个工厂(形式参数)可以想象成原材料将原材料里面的东西交给函数体原料经过函数体转化成成品再经过return返回回去自己定义好类型的成品。()里面的形式参数可以没有也可以设置多个。而函数名就可以想象成一个工厂的名字通过这个名字去找到这个工厂让他帮忙加工原材料。当你不想要返回的值的时候你可以设置为void类型。当我们想要去写一个加法函数的时候我们就能这么写#includestdio.h int Add(int x,int y) { return xy; } int main() { int r Add(3,5); printf(%d\n,r); return 0; } 结果显然易见8我们的函数名是Add形式参数是我们自己设置的 int类型的x和y函数体 return xy函数是灵活变换的 函数类型根据自己未来的需求来设置。取决于自己想要一个怎么样的函数怎么设置这个函数的功能未来都需要自己来设置。形参与实参就比如我们上面写的Add加法函数。当我们调用Add函数的时候传递3和5给Add函数这个3和5就是实际参数简称实参而在函数()里面设置的x、y就是形式参数简称形参。什么是形参实际上如果我们只定义了Add这个函数的时候而不去调用这个函数这个x和y只是在形式上存在也不会向内存去申请空间不是真实存在的。形参与实参的关系#includestdio.h int Add(int x,int y) { return xy; } int main() { int a 3; int b 5; int r Add(a,b); return 0; } 在我们的VS2022中调试窗口里面的监视可以看见我们的内存分布情况。我们在监视窗口可以看见我们的内存都不一样所以我们可以理解为形参是实参的一个临时的拷贝。注意 形参的改变不会影响实参。函数与return语句的关系:在我们自己写函数的过程中经常可以见到return语句。那么return语句到底有什么用1.return后面可以接一个表达式也能接一个值若是表达式先计算表达式里面得出的结果然后再返回回去。2.当我们的返回类型是void类型的时候return后面可以什么都不加。3.return语句执行完之后后面的代码将不会继续执行。4.return返回的值和自己设置的返回类型不同时系统会⾃动将返回的值隐式转换为函数的返回类型。5.若函数中有分支语句应确保每种情况都有返回值否则会出现编译错误。6.如果函数的返回类型不写编译器会默认返回类型为int7.如果函数写了返回值但是没有return语句那么返回的值是未知的。数组做为函数的参数在我们解决问题的时候难免会将数组传过去来解决问题在我们的函数内部对数组进行操作。例如写一个整型的数组再写一个函数将数组内的内容全部设置为1然后打印出来。#includestdio.h void test(int arr[],int n) { //将数组内容全部改为1 int i 0; for(i0;in;i) { arr[i] 1; } int j0; //打印数组的内容 for(j0;jn;j) { printf(%d ,arr[j]); } } int main() { int arr[]{1,2,3,4,5,6,7,8,9,10}; test(arr,10);//当数组在传参的时候传给函数的是函数的首元素的地址 return 0; } 在我们使用数组当参数的时候需要注意以下几点1.函数的形式参数要和实参匹配2.函数的实参是数组形式形参也是可以写成数组的形式。3.形参如果是一维数组大小可以不写但是形参要是二维数组二维数组的行能省略列不能够省略。4.数组传参的时候形参是不会重新创建数组的。5.数组的形参的名字可以和实参的相同。嵌套调用和链式访问嵌套调用就是函数之间互相调用就像乐高玩具零件在多个零件的作用下才能搭配出这个精美的乐高玩具。函数与函数之间的嵌套调用也是这样。例如假设我们想要知道某年某月有多少天我们可以设计两个函数来实现。#includestdio.h int is_leap_year(int year)//判断是不是闰年的函数 { if( (year%40) (year %100 ! 0) || (year %400 0) ) { return 1; } else return 0; } int get_year_month(int year,int month) { int days[]{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; int daydays[month];//得到不是闰年的天数 if( is_leap_year(year) month 2 )//判断是不是闰年 { day1; } return day; } int main() { int y 0; int m 0; scanf(%d %d,y,m); if(m 12 || m1) { printf(输入错误请选择1-12月的数字\n); return 1; } int r get_year_month(y,m);//用r来接收 printf(%d\n,r); return 0; } 这段代码完成了一个独立的功能在这个函数中我们也用了很多的函数如 printfscanf,return还有我们自己写的一个函数get_year_month ;is_leap_year。以后在我们写更大的代码的时候都是函数嵌套的但是函数是不能够嵌套定义的。函数的链式访问所谓的链式访问就是将函数的返回值作为另一个函数的参数就像链条一样将函数与函数之间串联起来。#includestdio.h #includestring.h int main() { printf(%d\n,strlen(abcdef) );//链式访问 return 0; }这就是简单的链式访问。现在我们来看一个有趣的代码#include stdio.h int main() { printf(%d, printf(%d, printf(%d, 43))); return 0; }输出的结果会是什么呢答案是4 3 2 1想要知道这个答案的来源我们首先得知道printf的返回值printf函数的返回值是打印在屏幕上的字符个数。上面例子中第一个printf的打印的是第二个函数的返回值第二个printf打印的是第三个printf的返回值第三个printf打印的就是43。第三个printf打印的是43返回值是2第二个printf打印的是2返回值是1第一个printf打印的是1最终打印的就是4321函数的声明和定义单个文件中注意当我们写的函数在主函数之前我们写的函数没有声明的话编译器也不会报错当我们写的函数在主函数之后如果没有函数的声明的话编译器就会报错。因为在主函数之前写的函数其实他的定义就是一种特殊的声明。 #includestdio.h int main() { //函数的声明 int is_leap_year(int year); int get_year_month(int year,int month); int y 0; int m 0; scanf(%d %d,y,m); if(m 12 || m1) { printf(输入错误请选择1-12月的数字\n); return 1; } int r get_year_month(y,m);//用r来接收 printf(%d\n,r); return 0; } int is_leap_year(int year)//判断是不是闰年的函数 { if( (year%40) (year %100 ! 0) || (year %400 0) ) { return 1; } else return 0; } int get_year_month(int year,int month) { int days[]{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; int daydays[month];//得到不是闰年的天数 if( is_leap_year(year) month 2 )//判断是不是闰年 { day1; } return day; } 多个文件一般我们在企业中写代码不可能用一个文件代码比较多也不可能将所以的代码都放在一个文件中我们往往会根据功能拆分为多个文件的形式。⼀般情况下函数的声明、类型的声明放在头⽂件.h中函数的实现是放在源⽂件.c⽂件中。static与extern:sstaticc和extern都是C语言中的关键字。static是静态的意思static可以用来1.修饰局部变量或者修饰全局变量2.修饰函数extern是用来声明外部符号的。生命周期变量的创建申请内存)到变量的销毁收回内存这个时间段作用周期是程序设计概念通常来说⼀段程序代码中所⽤到的名字并不总是有效可⽤ 的⽽限定这个名字的可⽤性的代码范围就是这个名字的作⽤域。static修饰局部变量如图所示这个局部变量加了static与没加的区别static延长了局部变量的生命周期。代码1的test1函数中的局部变量i是每次进⼊test函数先创建变量⽣命周期开始并赋值为0然后 再打印出函数的时候变量⽣命周期将要结束释放内存。代码2i的值有累加的效果其实test2函数中的i创建好后出函数的时候是不会销毁的重新进⼊函数也就不会重新创建变量直接上次累积的数值继续计算。static修饰局部变量改变了变量的生命周期本质上是因为static将局部变量的存储类型改变了。本来局部变量是放在栈区的static将局部变量存储到了静态区。存储在静态区的变量和全局变量一样。⽣命周期就和程序的⽣命周期⼀样了只有程序结束变量才销毁内存才 回收。但是作⽤域不变的。使⽤建议未来⼀个变量出了函数后我们还想保留值等下次进⼊函数继续使⽤就可以使⽤ static 修饰。static修饰全局变量当我们用static修饰age的时候会发生什么呢编译器会报错当我们想要用static修饰一个全局变量的时候static修饰的全局变量只能在修饰static的文件中使用。否则在编译过程中会出现链接性错误。即使用extern声明外部符号也无济于事。使⽤建议如果⼀个全局变量只想在所在的源⽂件内部使⽤不想被其他⽂件发现就可以使⽤ static 修饰。函数递归什么是函数的递归在c语言中递归是一种解决问题的方法。递归就是函数自己调用自己这一个过程。#includestdio.h int main() { main(); return 0; }在我看来这个代码是世界上最简单的一个递归函数。上面只是⼀个简单的递归程序只不过上⾯的递归只是为了演⽰递归的基本形式不是为了解决问 题代码最终也会陷⼊死递归导致栈溢出。递归的思想大事化小递归中递是递推而归就是回归。总不可能让我们自己的函数自己调用自己无线下去总有一个结束的条件。否则就会栈溢出。递归的限制条件当递归满足这个条件的时候就不再继续递归下去。例如当我们想要求一个数字的阶乘的时候我们就能够用递归的思想。#includestdio.h int test(int n) { if(n0) { return 1; } else return n*test(n-1); } int main() { int m0; scanf(%d,m); int r test(m); printf(%d\n,r); return 0; }结果这⾥不考虑n太⼤的情况n太大存在溢出有时候递归虽好但是也会引入一些问题所以我们⼀定不要迷恋递归适可而止就好。完——