Рекурсивная функция будет вызывать себя многократно. Бесконечный цикл будет просто продолжать выполнять один и тот же код многократно. Хотя это может звучать очень похоже, фактические эффекты очень разные. Каждый раз, когда вызывается метод, переменные заталкиваются в стек. Конечно, это означает, что существуют ограничения на количество повторений функции. Поэтому, хотя ваш бесконечный цикл будет выполняться вечно, рекурсивная функция на практике в конце концов исчерпает место в стеке, и приложение, скорее всего, остановится.
Рекурсивная функция вызывает себя, которая помещает параметры в стек. Это может продолжаться бесконечно, что в конечном итоге приведет к переполнению стека. Некоторые компиляторы могут оптимизировать это, по сути превращая рекурсивную функцию в цикл while - это называется хвостовой рекурсией.
Цикл while просто вернется наверх и снова будет использовать то же пространство, так что он может работать буквально вечно (по крайней мере, пока не отключится электричество: -))
Рекурсивная функция продолжает вызывать сама себя, тогда как бесконечный цикл продолжает повторять один и тот же блок кода.
При вызове функции необходимо зарезервировать некоторую память для хранения возвращаемого значения в стеке вызовов функций . Таким образом, при достаточном количестве рекурсивных вызовов функции пространство стека будет исчерпано и вызовет переполнение стека.
Примите во внимание
#include <stdlib.h>
#include <stdio.h>
int somefunc(int x) {
printf("%d\n", x);
return somefunc(rand());
}
int main(void) {
return somefunc(0);
}
Вышеупомянутая программа в конечном итоге завершится или нанесет серьезный ущерб, в отличие от
int somefunc(int x) {
return printf("%d\n", x);
}
int main(void) {
while ( 1 ) {
somefunc(rand());
}
return 0;
}
, которая будет успешно работать до тех пор, пока пользователь не завершит работу (нажатием CTRL-C или выключением компьютера .)
Когда функция вызывается, для нее выделяется некоторая память в стеке. Он сохраняет: - значения параметров, переданные в функцию - адрес возврата - адрес в памяти, по которому будет выполняться выполнение после возврата функции - локальные переменные - другие вещи которые зависят от реализации
Таким образом, каждый вызов функции в рекурсивной функции выделяет память. Так что будьте осторожны при проектировании.
В случае while (1) - процесс, выполняющий программу с бесконечным циклом, например, while (1) {;} просто повторяет некоторую часть команд. Поддержание такого процесса в рабочем состоянии в операционной системе, что просто требует времени процессора и некоторой памяти.
функция помещает в стек адрес возврата (место в памяти, откуда была вызвана следующая рекурсивная функция) и переходит к этому месту в памяти (к рекурсивной функции). {{1 }} И while не нужно хранить адрес ret, потому что он перескакивает только в начало.
Для простого кода и хорошего компилятора нет разницы, но для наивного компилятора с непрерывной рекурсивной функцией у вас закончится место в стеке , называется переполнением стека.
Что касается вопросов о том, что происходит: при переполнении стека: стек отображается в место или в память (для каждого процесса), рядом с которой не выделена память. Стек используется для хранения значений локальной функции, текущий адрес возврата функции также помещается в стек, а затем значения, переданные следующей функции, помещаются в стек. Таким образом потребляется стек для каждого вызова функции. Поэтому, когда ЦП пытается получить доступ к памяти, проходит конец выделенного пространства, что вызывает исключение доступа к памяти и интерпретируется как переполнение стека.
Некоторое время (1) поведение операционной системы зависит от того, какой режим многозадачности использует ваша ОС.Для упреждающей системы (например, Window NT и новее) он просто видит, что вашему процессу предстоит много работы, но если у него есть пользовательский интерфейс, и вы не отвечаете на отправляемые им оконные сообщения, вы получить классическое сообщение «Кажется, это приложение перестало отвечать».
Где, как если бы у вас была операционная система без упреждения, она зависнет, если вы не вернете управление ОС, то есть в дни Windows 3.1 драйвер принтера зависал бы во время печати всей системы. Ну, драйверы HP сделали.
Во встроенной системе, чтобы избежать блокировки программного обеспечения, у них обычно есть аппаратный таймер, называемый сторожевым таймером, который, если не «щелкать» каждую секунду, перезагружает систему. Таким образом предотвращается нахождение системы в заблокированном состоянии.
в то время как (1)
не создает новый контекст оценки, рекурсия (если не оптимизирована компилятором) создает. Это означает несколько вещей:
while (1)
одним простым return
, но return
только выходит из текущего контекста в рекурсии. Не так просто полностью выйти из множества вложенных контекстов. Рекурсивная функция может закончиться в зависимости от того, как она закодирована. Конечно, она не обязательно должна заканчиваться переполнением стека. while(1)
Цикл также может завершиться, если в нем есть прерывание или возврат.
У рекурсивной функции есть пункт, в котором она не вызывает сама себя, что означает, что она заканчивается.
В бесконечном цикле while (1) выделяет пространство стека для кадра стека (информация о том, куда вернуться, если / когда функция вернется ), и любые локальные переменные, объявленные в той же функции, будут размещены в стеке один раз, независимо от того, сколько итераций выполняет цикл.
Следовательно, для 1000000 итераций пространство стека будет размером sizeof (кадр стека) + sizeof (любые локальные переменные)
, поэтому, если кадр стека равен 16 байтам, а int равен 4 байтам, функция будет выделять 20 байтов на стек.
Принимая во внимание, что рекурсивная функция будет выделять пространство в стеке для кадра стека (информация о функции, в которую нужно вернуться) и любых локальных переменных каждый раз, когда функция вызывает себя.
Следовательно, для 1000000 итераций пространство стека будет (sizeof (кадр стека) + sizeof (любые локальные переменные)) * 100000
, поэтому (с использованием предыдущих размеров) 20 байтов * 1000000 == 20000000 байтов = = (приблизительно) 19 МБ