对于模块化程序的初步了解

一个真正的程序里面白喊自定义函数,也包含对应的头文件,还有函数定义界面。于是创建了个简单的加法函数。
函数的声明

#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;}

所以以上代码中还有一个,不用递归,直接用迭代实现的函数,一运行就能看到,两个函数实现目标的时间差,所以当,递归之中函数调用的次数过大时,运算量巨大,就很有必要使用其他手段实现目标。

更多相关文章

  1. JavaScript中的异步生成器函数[每日前端夜话0xC9]
  2. 输入两个整数调用puts函数,求两个整数的乘积
  3. VS中scanf等函数报错解决方法
  4. php ajax成功:函数(msg) -获取msg
  5. $ .post请求中的回调函数
  6. 利用jQuery的$.event.fix函数统一浏览器event事件处理
  7. 仅当鼠标停留在元素上时,jQuery才会激活鼠标悬停函数
  8. jQuery循环没有每个和回调函数
  9. JavaScript函数中的Ruby代码

随机推荐

  1. Android 卡片翻转效果
  2. Android中网络使用
  3. PopupWindow的应用 2
  4. Facebook工程师是如何改进他们Android客
  5. Android中使用Handler机制更新UI的两种方
  6. UserInfo.java
  7. Android(安卓)APP旋转屏幕
  8. Android中“分享”功能的实现
  9. Android/安卓存储优化
  10. AIDL踩坑