对于模块化程序的初步了解
一个真正的程序里面白喊自定义函数,也包含对应的头文件,还有函数定义界面。于是创建了个简单的加法函数。
函数的声明
#ifndef __ADD_H__
#define __ADD_H__
//函数的声明
int Add(int x, int y);
#endif
我将这个声明放在目录为add.h的文件下,其中的
#ifndef __ADD_H__
#define __ADD_H__
#endif
作用是为了防止函数连续被调用时整个函数的定义段被连续搬运,导致主程序的代码量过大。函数的调用原理是,讲函数定义目录下的代码经过头文件搬运到需要用的地方,然后执行。
函数的定义
int Add(int x, int y)
{
return (x + y);
}
放在目录为add.c的目录下,将对应功能的函数放在具有提示意义的目录下面,能够与他人更好的配合,具有可读性。
主函数
#include <stdio.h>
#include "add.h"
int main()
{
int a = 15;
int b = 25;
printf("sum=%d\n",Add(a, b));
return 0;
}
引用自定义函数的头文件时,用的是双引号 "" 。
最简单的递归
#include <stdio.h>
int main()
{
printf("haha\n");
main();
return 0;
}//递归常见的错误,栈溢出,stack overflow
这是一个没有限制条件的递归,程序运行一会儿就会自己停止,并且弹出警告窗口,原因是,程序运行的时候,会将运行时产生的局部变量存在名为堆栈的一个内存区域,这个没有限制的递归,不断的调用自身,不断的打印“haha”,就会将堆栈占满。
而这个程序也让人能理解,递归,就是函数对于自身的调用,用现在的网络流行语,俗称套娃。
设计一个递归函数 分别打印出1234里的1 2 3 4
void print(int n)
{
if (n > 9)
{
print(n / 10);
}
printf("%d ", n % 10);
}
#include <stdio.h>
int main()
{
int num = 0;
scanf("%d", &num);
print(num);
return 0;
}
第一次要使用递归进行实现某一个功能其实是 很没有头绪的,尽管听老师讲完了 ,程序也跟着打了出来,也看着调试一步步的调了,眼看着代码一行一行的走,尤其是函数里面的调用,到了最后一层,不满足调用条件的时候,程序运行窗口就一个一个的把字符打印出来了,我前期是比较没有理解,程序执行到这个地方是怎么一层一层的返回去的,就是忘记了程序执行到了哪里,老师画图讲解之后,才算是明白,一层一层的进来,也是要一层一层的出去。当最后一层不再满足条件执行完毕弹出之后,弹出到上一层之后,继续执行下一条语句,以此类推。
不创建临时变量,求字符串长度
先是写一个能实现求字符串从长度的函数,不考虑递归
最简单的当然是直接使用库函数计算字符串长度
#include <string.h>
int main()
{
strlen();
}
接下来用自定义函数
int my_strlen(char* str)
{
int count = 0;
while (*str != '\0')
{
count++;
str = str + 1;
}
return count;
}
整个字符串是无法直接被函数调用的,只能讲字符串的地址作为指针变量,指向字符串的第一个字符,调用进入函数之中,每次用完之后+1,直到看到‘\0’字符,字符串的长度计算停止。count就作为一个计数,记录字符串的长度。可是我们需要的是一个不用临时变量的函数实现这一功能。
#include <stdio.h>
int my_strlen(char* str)
{
if (*str != '\0')
return 1+my_strlen(str + 1);
else
return 0;
}//未使用临时变量进行计数,实现了求字符串长度
int main()
{
char arr[] = "bit";
int len = my_strlen(arr);//传送过去的是数组第一个元素的地址,并不是整个数组
printf("len = %d\n", len);
return 0;
}
递归还是一样,用画图的方法解释起来更容易理解,将程序执行的过程可视化,增强理解,有一定的限制条件,而且每一层调用函数都在使得限制条件更加接近不满足if语句,最终能够停止递归过程。俗称停止套娃。
递归和迭代 求阶乘
当理解了前面两个递归的例子之后,我也独立写出了这个求阶乘的递归代码,大概思路为,想要求出n!,先要求出(n-1)!,想要求出(n-1)!,先要求出(n-2)!,快进到想要求出2!,就先求出1!,所以还是对自身的不断调用,代码如下:
#include <stdio.h>
int Fac1(int n)
{
int num = 1;
int i = 0;
for (i = 1; i <= n; i++)
{
num = i * num;
}
return num;
}
int Fac2(int n)
{
int ret = 1;
if (n != 0)
ret = n * Fac2(n - 1);
else
return ret;
}
int main()
{
int n = 0;
scanf("%d", &n);
printf("%d!=%d\n",n, Fac1(n));
printf("%d!=%d\n",n, Fac2(n));
return 0;
}
其中也用了个for循环写了另一个函数实现目的。
求斐波那契数列的第n个
斐波那契数列,1 1 2 3 5 8...简单的说,就是想知道第n个,就得先知道第n-1个和第n-2个,要知道第n-1个和第n-2个,就得知道第n-2和n-3个,第n-3和n-4个...以此类推,可是递归求第n个,需要运算的次数,就是2^n+2^(n-1)+...+2^2+2次运算,当求到第40个以上的时候,程序已经有了很明显的等待,需要等待才能出结果,计算的次数其实已经很大,n每+1,运算次数就会多出两倍,运算时间也会多出两倍,代码如下:
#include <stdio.h>
int Fib1(int n)
{
if (n <= 2)
return 1;
else
return Fib1(n - 1) + Fib1(n - 2);
}
int Fib2(int n)
{
int a = 1, b = 1, c=0;
int i = 0;
if (n > 2)
{
for (i = 3; i <= n; i++)
{
c = a + b;
a = b;
b = c;
}
return c;
}
else
return 1;
}
int main()
{
int n = 0;
scanf("%d", &n);
int f2 = Fib2(n);
printf("第%d个斐波那契数列:%d\n", n, f2);
int f1 = Fib1(n);
printf("第%d个斐波那契数列:%d\n", n, f1);
return 0;
}
所以以上代码中还有一个,不用递归,直接用迭代实现的函数,一运行就能看到,两个函数实现目标的时间差,所以当,递归之中函数调用的次数过大时,运算量巨大,就很有必要使用其他手段实现目标。