时间:2023-02-16 09:33:20 | 栏目:C代码 | 点击:次
紧接上文,继续学习函数相关内容。
函数的定义是指函数的具体实现,交待函数的功能实现
一般写简单的求和函数,求和功能直接写在main( )函数了。
//简单的求和函数 int main() { int a = 10; int b = 20; int sum = a+b; printf("%d\n", sum); return 0; }
把加法功能单独写成一个函数,放在主函数前面。如果将函数add放在主函数后面,则会报错,因为程序自上而下进行的,主函数执行后,发现add函数未定义,找不到。
//之前的有函数的写法.函数放在前面 int add(int x, int y) { return x + y; } int main() { int a = 10; int b = 20; int sum = add(a, b); printf("%d\n", sum); return 0; }
int add(int x, int y);//函数的声明 int main() { int a = 10; int b = 20; int sum = add(a, b); printf("%d\n", sum); return 0; } int add(int x, int y)//定义放在主函数后面,需要先声明 { return x + y; }
实际上,当函数代码较多时,一般采用模块化编程,每个函数实现功能尽量单一,函数间要低耦合、高内聚。因此,针对上面的加单的加法函数,用带头文件的写法重写一遍。
先定义源文件 test.c 、源文件 add.c和头文件 add.h
//源文件test. c #include "add.h" int main() { int a = 10; int b = 20; int sum = add(a, b); printf("%d\n", sum); return 0; } //源文件add.c int add(int x, int y)//定义放在主函数后面,需要先声明 { return x + y; } //头文件add.h int add(int x, int y);//函数的声明
当编程写了一个减法的函数给别人用,但是又不想把源码直接分享给别人,这时候就可以将代码编译成静态库(就是.lib文件)。
静态库的特点:将函数编译成静态库,别人可以正常使用封装好的代码,但是又看不到源码。
下面举例说明,如何生成静态库(.lib):
新建VS工程,新建源文件 sub.c和 头文件 sub.h,编写一个减法函数 sub
//源文件 sub.c int sub(int x, int y)//函数定义需要先声明 { return y - x; } //头文件 sub.h int sub(int x, int y);
依次点击解决方案资源管理器——项目名称——右键选属性,弹出对话框。
然后依次点击——配置属性——常规——项目默认值——配置类型——下拉菜单选择静态库(.lib)——应用——确定。
接着点击生成——生成解决方案。
最终会在工程文件夹下的——Debug文件夹——看到静态库.lib文件。
用记事本打开静态库,可以看到是乱码。
接下来说明如何使用别人或者自己生成好的静态库文件:
(1)将函数对应的同名头文件.h文件 和 同名静态库.lib拷贝至自己的工程文件中。
(2)在头文件中添加上t头文件 sub0119.h
(3)在源文件中添加减法头文件引用 和静态库的引用,
#include "add.h"//加法头文件 #include "sub0119.h"//减法头文件 #pragma comment(lib,"sub0119.lib")//静态库必须加上
(4)程序运行时,会通过上面的引用将生成的静态库加载进来。在主函数直接使用 减法函数sub即可。
//带头文件的写法 int main() { int a = 10; int b = 20; int sum = add(a, b);//一般的函数调用 int subnum = sub(a, b);//使用静态库 printf("%d\n", sum); printf("%d\n", subnum); return 0; }
运行程序见下图:
接受一个整型值(无符号),按照顺序打印它的每一位。
输入:1234,输出 1 2 3 4
void print(num)//自定义打印函数 { int arr[10] = { 0 };//定义数组 for (int i = 0; i < 4; i++) {//将数字存放在数组里 arr[i] = num % 10;//取数字最后一位 num = num / 10;//取整数 } for (int i = 3; i >= 0; i--) {//倒着打印 printf("%d ", arr[i]); } } int main() { int num = 1234; print(num); return 0; }
分析:打印1234可以分解成下图那样拆解,分别把不同位上的数字取出,最终把数字拆解剩最后一位时,开始打印:
代码如下所示:
void print(int num) { if (num>9) { print(num/10); //取余 } printf("%d ",num % 10);//取模 } int main() { int num = 1234; print(num); return 0; }
通过调试,我们分析整个递归程序的运行逻辑见下图,红色圆圈的1 2 3 4表示程序的执行顺序:
此时函数已经拆解到最后一层了,函数执行结束返回到上一次调用的地方,绿色圆圈的1 2 3 4表示程序的返回顺序:
在函数运行过程中,每调用一次函数,在内存栈中就会开辟空间存放num的值,如下面蓝色方框显示,第一次调用函数存放的1234 在最底层, 以此类推,1是最后调用函数存放的,就在最上面。
在函数返回时,看绿色圆圈 1 2 3 4, num的值就从上向下取值,
运行结果见下图:
编写函数不允许创建临时变量,求取字符串的长度
//编写函数不允许创建临时变量,求取字符串的长度 void getlen(char* arr) { int count = 0;//计数 while (*arr!='\0') { count++;//计数加1 arr++;//地址移动到下一个字符 } printf("%d", count); } int main() { char arr[] = "abcd"; getlen(arr);//数组名就是首元素地址 return 0; }
分析:自定义函数getlen,计算字符串 abcd,字符串以 '\0’结尾,这是隐藏的,实际字符串为"abcd\0"自定义函数可以分解成下图那样拆解,每次取出一个字符,最终把字符都取完,返回值:
下面是实现代码:
//递归方法 int getlen(char* arr) { if (*arr != 0) { arr++; return 1 + getlen(arr); } return 0;//等于0,字符串结束了,返回0 } int main() { char arr[] = "abcd"; int sz = getlen(arr); printf("%d", sz); return 0; }
程序运行结果见下图,红色路线是递归按顺序调用函数,绿色的路线是递归达到限制条件后,返回值
求n的阶乘。(不考虑溢出)
//求n的阶乘 void fact(int n) { int num = 1; for (int i = 1; i <= n; i++) { num = num * i; } printf("%d", num); } int main() { fact(3);//阶乘 return 0; }
分析:自定义函数fact,求n的阶乘。自定义函数可以分解成下图那样拆解:
//递归方法 int fact(int n) { if (n >= 1) { return n*fact(n - 1); n--; } else { return 1; } } int main() { int num=fact(3);//阶乘 printf("%d", num); return 0; }
运行结果见下图:
求第n个斐波那契数。(不考虑溢出)
//一般方法 void fib(int n) { int num1 = 1; int num2 = 1; int num3 = 0; for (int i = 1; i <=(n-2); i++) { num3 = num1 + num2; num1 = num2; num2 = num3; } printf("%d", num3);//输出5 } int main() { fib(5);//第五个斐波那契数列是5 return 0; }
分析:自定义函数fib,求第n个斐波那契数列。自定义函数可以分解成下图那样拆解:
//递归方法方法 int fib(int n) { if (n <= 2) { return 1; } return fib(n - 1) + fib(n - 2); } int main() { int num=fib(5); printf("%d", num); return 0; }
在前面小节练习4中,发现有一个问题,举例fib(6)说明,下面是计算fib(6)时用的递归方法,分析会发现fib(3)居然重复计算了3次,如果计算fib(40)时,这样的重复计算会更多,大量的重复计算势必会降低计算速度。
通过程序来验证一样,计算fib(6)时,fib(3)总共计算了几次:
int count = 0;//全局变量 int fib(int n) { if (n == 3) count++;//计算fib(3)计算了多少次 if (n <= 2) return 1; return fib(n - 1) + fib(n - 2); } int main() { int num=fib(6); printf("%d\n", num); printf("%d\n", count); return 0; }
结果如下所示:fib(6) = 8,fib(3)总共计算了3次:**
当计算fib(40)时,fib(3)总共计算了几次?
结果见下图,fib(40) = 102334155,fib(3)总共计算了39088169次,惊呆了居然3千多万次。而且很耗时间,计算效率低。
而用一般的方法计算fib(40)时,fib(3)只计算了一次。
那如何解决上述的问题:
函数的学习暂时告一段落,涉及到的递归函数的实现不太好理解,这块要加大练习,才能逐渐掌握,重要的就是抽丝剥茧,找到限制条件,然后返回确定的值。
下一篇博文开始数组的学习了。