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

看代码

#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.exe
GNU gdb (GDB) 7.4
Copyright (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) l
1       #include <stdio.h>
2
3       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) l
Line number 11 out of range; 4.3.1_递归阶乘.c has 10 lines.
(gdb) b f
Breakpoint 1 at 0x4013bd: file 4.3.1_.c, line 4.
(gdb) s
The program is not being run.
(gdb) r
Starting program: H:\\2\\a.exe
[New Thread 3640.0x2420]

Breakpoint 1, f (n=5) at 4.3.1_递归阶乘.c:4
4               return n == 0?1:f(n-1)*n;
(gdb) s

Breakpoint 1, f (n=4) at 4.3.1_递归阶乘.c:4
4               return n == 0?1:f(n-1)*n;
(gdb) s

Breakpoint 1, f (n=3) at 4.3.1_递归阶乘.c:4
4               return n == 0?1:f(n-1)*n;
(gdb) s

Breakpoint 1, f (n=2) at 4.3.1_递归阶乘.c:4
4               return n == 0?1:f(n-1)*n;
(gdb) s

Breakpoint 1, f (n=1) at 4.3.1_递归阶乘.c:4
4               return n == 0?1:f(n-1)*n;
(gdb) s

Breakpoint 1, f (n=0) at 4.3.1_递归阶乘.c:4
4               return n == 0?1:f(n-1)*n;
(gdb) s
5       }

可以直接使用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) s

Breakpoint 1, f (n=4) at 4.3.1_递归阶乘.c:4
4               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) s

Breakpoint 1, f (n=3) at 4.3.1_递归阶乘.c:4
4               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) s

Breakpoint 1, f (n=2) at 4.3.1_递归阶乘.c:4
4               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) s

Breakpoint 1, f (n=1) at 4.3.1_递归阶乘.c:4
4               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) s

Breakpoint 1, f (n=0) at 4.3.1_递归阶乘.c:4
4               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) s
5       }
(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) s
5       }
(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) s
5       }
(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) s
5       }
(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) s
5       }
(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) s
5       }

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

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

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

(gdb) r
Starting 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:4
4               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段用于存储未赋值的全局变量和所需的空间,所以每次递归调用都需要

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

时间: 2024-12-25 13:01:03

算法竞赛入门经典_4.3_递归的相关文章

《算法竞赛入门经典(第二版)》pdf

下载地址:网盘下载 内容简介  · · · · · · <算法竞赛入门经典(第2版)>是一本算法竞赛的入门与提高教材,把C/C++语言.算法和解题有机地结合在一起,淡化理论,注重学习方法和实践技巧.全书内容分为12 章,包括程序设计入门.循环结构程序设计.数组和字符串.函数和递归.C++与STL入门.数据结构基础.暴力求解法.高效算法设计.动态规划初步.数学概念与方法.图论模型与算法.高级专题等内容,覆盖了算法竞赛入门和提高所需的主要知识点,并含有大量例题和习题.书中的代码规范.简洁.易懂,不

棋盘覆盖问题(算法竞赛入门经典)

在一个 2^k * 2^k 个方格组成的棋盘中,若恰有一个方格与其它方格不同,则称该方格为一特殊方格,称该棋盘为一特殊棋盘.显然特殊方格在棋盘上出现的位置有 4^k 种情形.因而对任何 k>=0 ,有 4^k 种不同的特殊棋盘.下图所示的特殊棋盘为 k=2 时 16 个特殊棋盘中的一个. 在棋盘覆盖问题中,要用下图中 4 中不同形态的 L 型骨牌覆盖一个给定的特殊棋牌上除特殊方格以外的所有方格,且任何 2 个 L 型骨牌不得重叠覆盖.易知,在任何一个 2^k * 2^k 的棋盘中,用到的 L 型

拓扑排序(算法竞赛入门经典)

拓扑排序的定义: 把每个变量看成一个点,”小于“或者”先后“关系看成有向边,则我们得到一个有向图.这样我们的任务实际上是把一个图的所有节点排序,使每一条有向边的(u,v)对应的u都排在v之前,在图论中,我们称之为拓扑排序.不难发现,如果一个有向图里存在回路,则不存在拓扑排序(如果设置一个标志数组,我们可以发现回路中的点一直处于正在被访问状态,这可以作为拓扑排序的结束条件). 我们先看一个样例: 下面我们用邻接矩阵存储这张图:   0 1 2 3 0 0 1 1 1 1 0 0 1 1 2 0 0

《算法竞赛入门经典第二版》 P35 习题2-4 子序列的和(subsequence)

/* <算法竞赛入门经典第二版> P35 习题2-4: 输入两个正整数 n < m < 10^6,输出 (1/n)^2 + 1/(n+1)^2 +……+ 1/m^2,保留5位小数. 输入包含多组数据,结束标志为 m=n=0. 有错欢迎指出^_^ */ #include<stdio.h> int main() { int m,n,i,j=1; while(scanf("%d%d",&m,&n) != EOF) { double sum

《算法竞赛入门经典》动态规划复习

codevs 4979 数塔 1 #define N 100 2 #include<iostream> 3 using namespace std; 4 #include<cstdio> 5 int a[N][N],b[N][N],n; 6 int main() 7 { 8 scanf("%d",&n); 9 for(int i=1;i<=n;++i) 10 for(int j=1;j<=i;++j) 11 { 12 scanf("

算法竞赛入门经典训练指南

最近在看算法竞赛入门经典训练指南这本书,书中不错的算法我将在博客中发布,和大家共同学习. 题目: 在你的王国里有一条n个头的恶龙,你希望雇一些骑士把它杀死(即砍掉所有头).村里有m个骑士可以雇佣,一个能力值为m的骑士可以砍掉一个直径不超过x的头,且需要支付x个金币.如何雇佣骑士才能砍掉恶龙的所有头,且需要支付的金币最少?注意,一个骑士只能砍一个头(且不能被雇佣两次). 输入格式: 输入包含多组数据.每组数据的第一行为正整数m和n(1<=m,n<=20 000):以下m行每行为一个整数,即恶龙每

算法竞赛入门经典-训练指南(10881-Piotr&#39;s Ants)

题目大意: 一根长度为L的木棍一堆蚂蚁爬,向左或向右,速度都为1,若两蚂蚁碰撞则同时转头(转身时间忽略不计),问T时间之后每只蚂蚁的位置: 输入:t,(t个样例),每个样例输入 L,T,n,接下来是n行每行两个数据,一个POS(位置),一个dir(方向): 输出:按输入顺序输出每只蚂蚁的最终位置,若处于碰撞状态则输出Turning,掉下去输出"Fell off": 解题思路: 本题类似于<挑战程序设计>的一道水题(POJ -1852  Ants),思路题:不过本题输入并不一

算法竞赛入门经典+挑战编程+USACO

下面给出的题目共计560道,去掉重复的也有近500题,作为ACMer Training Step1,用1年到1年半年时间完成.打牢基础,厚积薄发.   一.UVaOJ http://uva.onlinejudge.org  西班牙Valladolid大学的程序在线评测系统,是历史最悠久.最著名的OJ.   二.<算法竞赛入门经典> 刘汝佳  (UVaOJ  351道题)  以下部分内容摘自:http://sdkdacm.5d6d.com/thread-6-1-1.html   "AO

【算法竞赛入门经典】【第三章】课后习题(第二部分)

自从蓝桥杯之后,都没写博客了.今天将之前第三章还差的一部分习题答案补上. 3-4整数相加 这一题题目有提示,说选择合适的输入方式,即可简化问题.刚开始没想到cin,结果还用字符串来做,多亏别人提醒我一下,我才想起cin.惭愧啊.. #include <iostream> using namespace std; int main() { int a,b; char op; while(cin>>a>>op>>b){ switch(op){ case '+':