Во-первых, у нас есть небольшая рекурсивная функция, такая как знаменитая серия fibonacci.

Как мы, возможно, знаем, последовательность Фибоначчи имеет несколько начальных условий, во-первых, встречаются числа 1 и 0, и если это число, отличное от этих двух, просто вычислите функцию по формуле fib (n-1) + fib (n -2). Вот краткий код C:

#include ‹stdio.h›

int fib (int n)
{
if (n == 0)
return 0;
else if (n == 1)
return 1;
else
return fib (n-1) + fib (n-2);
}

int main (int argc, char * argv []) {
int n = 5;
printf («Вычисление фибоначчи числа% d \ n», n);
printf («% d \ n ”, fib (n));
return 0;
}

На данный момент это довольно легко понять. Давайте скомпилируем его с помощью команды: ”gcc -g -o fibonacci‹ nameoftheCfile.c ›” Как только мы его получим, давайте посмотрим, что там внутри. Выполните команду «gdb ./fibonacci», приступим к отладке.

Внутри GDB

Давайте поместим точку останова в строку номер 5, для этого просто введите «b 5» или «break 5» и начните запускать программу с помощью команды «run».

Как мы видим на картинке, программа работает до тех пор, пока не достигнет установленной ранее точки останова. Если мы выполним команду bt, мы увидим два символа «#», указывающие количество кадров стека, с которыми мы имеем дело. Но что такое стековые фреймы?

Кадр стека - это кадр данных, который помещается в стек. В случае стека вызовов кадр стека будет представлять вызов функции и данные ее аргумента.

Итак, мы можем видеть фрейм стека №1, который является основной функцией, и фрейм стека №0, который является функцией fib. Легко, правда? давайте сделаем шаг вперед с командой s (что говорит само за себя!), пока мы снова не достигнем точки останова (это то, что есть с рекурсивными функциями). Здесь мы видим, что появился новый стековый фрейм, это fib (n = 4). Как известно, следует ожидать n = 3 и n = 2. Просто повторяйте тот же процесс, пока мы не дойдем до фибры (n = 2).

Итак, теперь мы видим fib (n = 2) и все 5 фреймов стека, но откуда мы знаем, что fib (2) происходит от fib (3), а не от fib (4) ??? Чтобы доказать это, давайте сделаем информационный фрейм 0, 1 и 2, чтобы проверить обратный адрес.

Как мы видим, фрейм вызывается последним, мы видим, что адрес фрейма 0x7fffffffe000 [который является фреймом стека № 1 - ›fib (n = 3)] вызывается в фрейме стека № 0 [ который является fib (n = 2) и имеет фрейм стека по адресу 0x7ffffffffdfd0]. Другими простыми словами, fib (2) был вызван fib (3).

Если мы продолжим выполнение и продолжим проверять стек, то мы увидим, что fib (2) вызовет fib (1). В этот момент fib (1) попадет в базовое условие и вернется, и будет вызвана вторая часть оператора return в fib (2) (return fib (1) + fib (0)), которая называется fib (0).

Теперь, когда мы прошли всю рекурсию, значения возвращаются к каждому вызову кадра. Был вычислен fib (2), который требовался для fib (3), который требовался для fib (4), который требовался от fib (5).