2010-04-06 3 views
12

Я играл с рекурсией и выполнял эту простую функцию. Я предполагал, что он выведет 9-0 в stdout, но он печатает 0-9. Я не вижу, как это происходит вообще.Эта рекурсивная функция меня озадачивает, что происходит?

int main() 
{ 
     rec(10); 
     return 0; 
} 

int rec(int n){ 
     if(n > 0) 
       printf("%d\n", rec(n -1)); 
     return n; 
} 
+7

Если приведенные ниже пояснения не «нажмите», вам может потребоваться выполнить хотя бы выполнение в отладчике, чтобы узнать, что происходит. –

+0

Кстати, в то время как хороший программист, как ожидается, сможет прочитать эту функцию (во время интервью возможно?), Они никогда не должны писать такой код. Хороший код не должен заставлять вас думать. –

ответ

9

Как говорит Майкл Барр в комментариях, если вы хотите увидеть, что происходит, компилировать с символами отладки включен, например:

gcc -o test -g test.c 

Затем запустите gdb.

gdb test 

Затем, чтобы начать вещи, идущие, тип

start 

нарушающий при первом вызове в основной функции. Тип

step 

, чтобы добраться до следующей строки в коде, и с тех пор, просто нажмите клавишу ВВОД, чтобы повторять последнюю команду. Если вы счастливы, введите continue, чтобы остановить переход. Вы увидите значения и оцениваемые строки на каждом этапе, которые подтвердят приведенные выше ответы.

Надеюсь, что предоставит некоторую полезную информацию.

+1

Другой полезной командой GDB является 'list', который показывает вам некоторые строки из вашего исходного файла. –

+0

@Thomas не стесняйтесь редактировать ни в чем, что вам кажется полезным! – 2010-04-06 22:28:11

+0

Спасибо, это здорово. У меня нет слишком большого опыта работы с gdb, так что это прекрасно. Я попробую. – Fred

19

rec функция на printf линии вычисляется до самого printf. Таким образом, самый глубокий пример функции rec напечатан первый.

+0

Я предполагаю, что меня смутил тот факт, что printf также является частью функции rec. Спасибо за объяснение, я только начал с этого. – Fred

+0

Без проблем, рад помочь. Просто помните, что оценка функций всегда идет наизнанку: параметры оцениваются перед функцией. – tloflin

11

Подумайте об этом.

rec(10) 
rec(9) 
rec(8) 
rec(7) 
rec(6) 
rec(5) 
rec(4) 
rec(3) 
rec(2) 
rec(1) 
rec(0) 

Start разматывать

printf("%d\n", 0); 
printf("%d\n", 1); 
printf("%d\n", 2); 
printf("%d\n", 3); 
printf("%d\n", 4); 
printf("%d\n", 5); 
printf("%d\n", 6); 
printf("%d\n", 7); 
printf("%d\n", 8); 
printf("%d\n", 9); 
+0

Спасибо, это хорошее объяснение. Я также посмотрю в отладчике, как это было предложено. – Fred

10

Давайте перепишем код, как это:

int rec(int n){ 
     if(n > 0) 
     { 
       int retval = rec(n -1); 
       printf("%d\n", retval); 
     } 
     return n; 
} 

Есть ли понять, почему 0 печатается первым, прежде чем 9?

+0

Обычно я устанавливаю такие функции, если я намерен их распечатать. Это факт, что printf также является частью функции rec, которая меня смутила, я думаю. Спасибо – Fred

3

Поскольку вы создаете 9 амбиций 9 > 8 > 7 > 6 > 5 > 4> 3 > 2 > 1 > 0, теперь эти объекты обрабатываются одинаково, это будет a(b(c(d(e(f(g())))))), переходя от самого глубокого к первому.

Помните, что когда вы делаете это printf("%d",n(m));, вы ничего не печатаете, вы говорите «распечатайте результат n (m)», а затем, когда он пытается разрешить n (m), вы вызываете другую печать и говоря еще раз «разрешить n (m-1)».

Теперь, когда вы дойдете до п (0) вернет 0 для печати последним вызовом printf, поэтому он печатает 0, то 1 .. 9.

+0

Спасибо, это очень полезно! Я не очень много рекурсии, но раньше решил начать эксперименты. В этом есть смысл. – Fred

0
int main() 
{ 
     rec(10); 
     return 0; 
} 

int rec(int n){ 
     if(n > 0) 
       printf("%d\n", rec(n -1)); 
     return n; 
} 

В общем, рассмотрим какую-нибудь кода. Мы говорим, что существует прямая связь между итерационными и рекурсивными решениями, так что любое решение можно записать итеративно и наоборот. Однако в некоторых случаях легче выразить алгоритм рекурсивно (например, Башня Ханоя.) В случае кода выше эквивалент будет конструкцией for loop.

Это может быть реализован в виде функции следующим образом:

void _for(int i, int n) 
{ 
    if(i >= n) return; // TERMINAL<br /> 
    // some expression (ie. printf("%d\n",i);)<br /> 
    _for(i+1,n) // RECURSION<br /> 
} 

Заметим, что это может быть расширена с помощью указателей на функции.

+0

Возможно, вы захотите проверить частоту редактора заметок. http://stackoverflow.com/editing-help – ChaosPandion

Смежные вопросы