算法竞赛入门经典_4.3_递归

来源:互联网 发布:unity3d js教程 编辑:程序博客网 时间:2024/05/21 23:52
看代码

#include <stdio.h>int f(int n){    return n == 0?1:f(n-1)*n;}int main(){    printf("%d\n", f(5));    return 0;}

上面f函数使用了递归,递归由两部分组成,一是递归头,二是递归体。

我们使用gcc调试工具

H:\编程书籍学习\算法竞赛入门经典2代码\算法入门经典第四章>b f'b' 不是内部或外部命令,也不是可运行的程序或批处理文件。H:\编程书籍学习\算法竞赛入门经典2代码\算法入门经典第四章>gdb a.exeGNU gdb (GDB) 7.4Copyright (C) 2012 Free Software Foundation, Inc.License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>This is free software: you are free to change and redistribute it.There is NO WARRANTY, to the extent permitted by law.  Type "show copying"and "show warranty" for details.This GDB was configured as "i686-pc-mingw32".For bug reporting instructions, please see:<http://www.gnu.org/software/gdb/bugs/>...Reading symbols from H:\编程书籍学习\算法竞赛入门经典2代码\算法入门经典第四章\a.exe...done.(gdb) l1       #include <stdio.h>23       int f(int n){4               return n == 0?1:f(n-1)*n;5       }6       int main()7       {8               printf("%d\n", f(5));9               return 0;10      }(gdb) lLine number 11 out of range; 4.3.1_递归阶乘.c has 10 lines.(gdb) b fBreakpoint 1 at 0x4013bd: file 4.3.1_.c, line 4.(gdb) sThe program is not being run.(gdb) rStarting program: H:\\2\\a.exe[New Thread 3640.0x2420]Breakpoint 1, f (n=5) at 4.3.1_递归阶乘.c:44               return n == 0?1:f(n-1)*n;(gdb) sBreakpoint 1, f (n=4) at 4.3.1_递归阶乘.c:44               return n == 0?1:f(n-1)*n;(gdb) sBreakpoint 1, f (n=3) at 4.3.1_递归阶乘.c:44               return n == 0?1:f(n-1)*n;(gdb) sBreakpoint 1, f (n=2) at 4.3.1_递归阶乘.c:44               return n == 0?1:f(n-1)*n;(gdb) sBreakpoint 1, f (n=1) at 4.3.1_递归阶乘.c:44               return n == 0?1:f(n-1)*n;(gdb) sBreakpoint 1, f (n=0) at 4.3.1_递归阶乘.c:44               return n == 0?1:f(n-1)*n;(gdb) s5       }

可以直接使用b f给函数设置断点,断点将设置在函数首部。使用s 进行单步执行,r运行

(gdb) bt#0  f (n=5) at 4.3.1_递归阶乘.c:4#1  0x004013f6 in main () at 4.3.1_递归阶乘.c:8(gdb) sBreakpoint 1, f (n=4) at 4.3.1_递归阶乘.c:44               return n == 0?1:f(n-1)*n;(gdb) bt#0  f (n=4) at 4.3.1_递归阶乘.c:4#1  0x004013cf in f (n=5) at 4.3.1_递归阶乘.c:4#2  0x004013f6 in main () at 4.3.1_递归阶乘.c:8(gdb) sBreakpoint 1, f (n=3) at 4.3.1_递归阶乘.c:44               return n == 0?1:f(n-1)*n;(gdb) bt#0  f (n=3) at 4.3.1_递归阶乘.c:4#1  0x004013cf in f (n=4) at 4.3.1_递归阶乘.c:4#2  0x004013cf in f (n=5) at 4.3.1_递归阶乘.c:4#3  0x004013f6 in main () at 4.3.1_递归阶乘.c:8(gdb) sBreakpoint 1, f (n=2) at 4.3.1_递归阶乘.c:44               return n == 0?1:f(n-1)*n;(gdb) bt#0  f (n=2) at 4.3.1_递归阶乘.c:4#1  0x004013cf in f (n=3) at 4.3.1_递归阶乘.c:4#2  0x004013cf in f (n=4) at 4.3.1_递归阶乘.c:4#3  0x004013cf in f (n=5) at 4.3.1_递归阶乘.c:4#4  0x004013f6 in main () at 4.3.1_递归阶乘.c:8(gdb) sBreakpoint 1, f (n=1) at 4.3.1_递归阶乘.c:44               return n == 0?1:f(n-1)*n;(gdb) bt#0  f (n=1) at 4.3.1_递归阶乘.c:4#1  0x004013cf in f (n=2) at 4.3.1_递归阶乘.c:4#2  0x004013cf in f (n=3) at 4.3.1_递归阶乘.c:4#3  0x004013cf in f (n=4) at 4.3.1_递归阶乘.c:4#4  0x004013cf in f (n=5) at 4.3.1_递归阶乘.c:4#5  0x004013f6 in main () at 4.3.1_递归阶乘.c:8(gdb) sBreakpoint 1, f (n=0) at 4.3.1_递归阶乘.c:44               return n == 0?1:f(n-1)*n;(gdb) bt#0  f (n=0) at 4.3.1_递归阶乘.c:4#1  0x004013cf in f (n=1) at 4.3.1_递归阶乘.c:4#2  0x004013cf in f (n=2) at 4.3.1_递归阶乘.c:4#3  0x004013cf in f (n=3) at 4.3.1_递归阶乘.c:4#4  0x004013cf in f (n=4) at 4.3.1_递归阶乘.c:4#5  0x004013cf in f (n=5) at 4.3.1_递归阶乘.c:4#6  0x004013f6 in main () at 4.3.1_递归阶乘.c:8(gdb) s5       }(gdb) bt#0  f (n=0) at 4.3.1_递归阶乘.c:5#1  0x004013cf in f (n=1) at 4.3.1_递归阶乘.c:4#2  0x004013cf in f (n=2) at 4.3.1_递归阶乘.c:4#3  0x004013cf in f (n=3) at 4.3.1_递归阶乘.c:4#4  0x004013cf in f (n=4) at 4.3.1_递归阶乘.c:4#5  0x004013cf in f (n=5) at 4.3.1_递归阶乘.c:4#6  0x004013f6 in main () at 4.3.1_递归阶乘.c:8(gdb) s5       }(gdb) bt#0  f (n=1) at 4.3.1_递归阶乘.c:5#1  0x004013cf in f (n=2) at 4.3.1_递归阶乘.c:4#2  0x004013cf in f (n=3) at 4.3.1_递归阶乘.c:4#3  0x004013cf in f (n=4) at 4.3.1_递归阶乘.c:4#4  0x004013cf in f (n=5) at 4.3.1_递归阶乘.c:4#5  0x004013f6 in main () at 4.3.1_递归阶乘.c:8(gdb) s5       }(gdb) bt#0  f (n=2) at 4.3.1_递归阶乘.c:5#1  0x004013cf in f (n=3) at 4.3.1_递归阶乘.c:4#2  0x004013cf in f (n=4) at 4.3.1_递归阶乘.c:4#3  0x004013cf in f (n=5) at 4.3.1_递归阶乘.c:4#4  0x004013f6 in main () at 4.3.1_递归阶乘.c:8(gdb) s5       }(gdb) bt#0  f (n=3) at 4.3.1_递归阶乘.c:5#1  0x004013cf in f (n=4) at 4.3.1_递归阶乘.c:4#2  0x004013cf in f (n=5) at 4.3.1_递归阶乘.c:4#3  0x004013f6 in main () at 4.3.1_递归阶乘.c:8(gdb) s5       }(gdb) bt#0  f (n=4) at 4.3.1_递归阶乘.c:5#1  0x004013cf in f (n=5) at 4.3.1_递归阶乘.c:4#2  0x004013f6 in main () at 4.3.1_递归阶乘.c:8(gdb) s5       }

使用bt查看调用栈,很容易理解递归调用的关系了,

注:由于使用了调用栈,c语言支持递归,调用自己和调用其他函数,并没有本质上的不同

 

在这里,我们把主函数中的5改成1000000,gdb运行之后显示如下

(gdb) rStarting program: H:\\2\\a.exe[New Thread 4372.0x1e78]Program received signal SIGSEGV, Segmentation fault.0x004013c7 in f (n=1899934856) at 4.3.1_递归阶乘.c:44               return n == 0?1:f(n-1)*n;

Segmentation fault段错误。什么原因呢?

H:\编程书籍学习\算法竞赛入门经典2代码\算法入门经典第四章>size a.exe   text    data     bss     dec     hex filename  23448    1324    2608   27380    6af4 a.exe

我们首先使用q退出刚才的gbd,使用size命令得到可执行文件中的各个段的大小

其中text为正文段,data为数据段,bss段,总大小是27380,。

注:正文段用于存储指令,数据段用来存储已初始化的全局变量,

bss段用于存储未赋值的全局变量和所需的空间,所以每次递归调用都需要

调用栈里面的栈帧,而当越界了,就是栈溢出