Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java: Общие вопросы > как происходит рекурсивный вызов


Автор: Pawl 4.1.2012, 11:35
Доброго времени суток. Когда "помогал" своему товарищу делать к зачету программки по теме рекурсия, понял, что сам в этом деле не все понимаю. Так, например, есть код, который с помощью рекурсии выводит на экран сначала +, потом - элементы массива. При элементе, равном 0, вывод заканчивается. Код этот я нашел на делфи и из спортивного интереса переделал его на яву. Привожу обе программки:
Код

program ex;

{$APPTYPE CONSOLE}

uses
  SysUtils;

Type mas = array[1..10] of real;

var x : mas;
    i : integer;

Procedure print(var x : mas; i : integer);
begin
    if x[i] = 0 then
      Writeln('***')
    else
    begin
      if x[i] > 0 then
        writeln('[', i : 1, '] ' , x[i]:2:1);
      print(x, i + 1);
      if x[i] < 0 then
        writeln('[', i : 1, '] ' , x[i]:2:1);
    end;
end;

begin
  i := 0;
  repeat
    inc(i);
    read(x[i]);
  until x[i] = 0;
  print(x, 1);
  readln;
  readln;
end.

Код

public class Ex {
    public static int[] x = {-1, -2, 3, 4, -5, -9, 0};
    public static int i, o, p;

    public static void printing(int []x, int i) {
        if (x[i] == 0) {
            System.out.println("***");
        } else {
         if (x[i] < 0) {
                System.out.println("[" + i + "] " + x[i]);
         }
            
            printing(x, i + 1);
            
            if (x[i] > 0) {
                System.out.println("[" + i + "] " + x[i]);
            }            
        }
    }

    public static void main (String...args) {
        printing(x, 0);
    }
}

Так все работает прекрасно, но когда я в коде на делфи заменил рекурсивную строку print(x, i + 1); на print(x, inc(i)); на этапе компиляции у меня появилась ошибка
Код

[DCC Error] Project1.dpr(21): E2010 Incompatible types: 'Integer' and 'procedure, untyped pointer or untyped parameter'

Ну ладно, возможно при замене операции i + 1 на операцию inc(i) действительно может возникнуть несоответствие типов. В ява инкремент встроен, поэтому там возникла другая ошибка: при замене в рекурсии i + 1 на i++, сначала много раз вывелся 0-вой элемент массива, а затем произошло переполнение стека:
Код

Exception in thread "main" java.lang.StackOverflowError

Конечно, при вставке в рекурсивный вызов i++ вместо i + 1, изменяется само значение i, и, скорее всего, в этом все дело, но если заменить i++ на ++i, программа опять таки заработает нормально. Я понимаю разницу между i++ и ++i, но не совсем понимаю, как это работает в рекурсии. Буду очень благодарен, если кто-нибудь мне доходчиво объяснит.
Спасибо!

Автор: FewG 4.1.2012, 13:28
Цитата(Pawl @ 4.1.2012,  11:35)
Конечно, при вставке в рекурсивный вызов i++ вместо i + 1, изменяется само значение i, и, скорее всего, в этом все дело, но если заменить i++ на ++i, программа опять таки заработает нормально. Я понимаю разницу между i++ и ++i, но не совсем понимаю, как это работает в рекурсии. Буду очень благодарен, если кто-нибудь мне доходчиво объяснит.
Спасибо!

Здесь как раз дело в разнице между i++ (постинкремент) и ++i (преинкремент). С i++ код работает не верно, ведь при вызове

Код
printing(x, i++)

Методу передается 0, ибо int i не был еще инкрементирован -> значит для следующего вызова 

Код
printing(x, i++)


i будет всё ещё равен 0 и так далее пока стек не будет переполнен.

С преинкрементом другое дело, перед тем как передать значение int i, оно будет увеличенно на 1.

Автор: Pawl 4.1.2012, 14:57
Цитата

Здесь как раз дело в разнице между i++ (постинкремент) и ++i (преинкремент)

Спасибо, я, в принципе, так и думал.

Добавлено через 26 секунд
Тема закрыта

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)