program StackOverflow;
function BadFactorial(k: integer): integer;
begin
BadFactorial := k*BadFactorial(k-1);
end;
begin
try
Writeln(BadFactorial(5));
except
Writeln('Исключение');
end;
end.
Код перепроверил - скорее всего проблема в самом .NET. Код на C# работает точно так же:
using System;
namespace Example
{
class Program
{
public static int BadFactorial(int k){
return BadFactorial(k - 1);
}
public static void Main(string[] args)
{
try{
Console.WriteLine(BadFactorial(5));
}
catch{
Console.WriteLine("Исключение");
}
}
}
}
Дело в том, что StackOverflow это особое исключение. Чтоб обработать исключение - надо ещё дополнительное место на стеке, но раз его уже и так нет - то и обработать его не получается.
In the .NET Framework 1.0 and 1.1, you could catch a StackOverflowException object (for example, to recover from unbounded recursion). Starting with the .NET Framework 2.0, you can’t catch a StackOverflowException object with a try/catch block, and the corresponding process is terminated by default.
. @Gleb, для BadFactorial Вы могли бы использовать epxression-body запись метода, в PascalABC.Net аналог, в некотором смысле, данной фичи - это:
function BadFactorial(k: integer): integer := k * BadFactorial(k - 1);
Вообще, плохой практикой считается создавать подпрограммы с неконтролируемым уровнем рекурсии.
Даже если в функции BadFactorial будет стоять if, вырубающий программу - этот код всё равно может вызвать ошибку, если передать большой k.
Кроме того, JIT не может оптимизировать этот код, и он и без того будет ужасно медленным.
Но, всегда есть способ заменить рекурсию обычным кодом. Именно всегда, это как то логически доказывается, не помню как.
К примеру:
function Factorial(k: integer): integer;
begin
Result := 1;
for var i := 2 to k do
Result *= i;
end;
begin end.
Ну, это простой пример. В более сложных, к примеру, в программе которая читает и выполняет скрипты в которых может содержаться рекурсия - можно не использовать стандартную рекурсию, а вместо этого, создать переменную типа Stack<*Запись, содержащая данные о точке вызова*>. И при каждом рекурсивном вызове - добавлять координаты откуда произошёл вызов - в эту переменную. В таком случае вы сами решаете, сколько уровней рекурсии разрешено, и что делать когда их становится слишком много.
Вы меня не поняли. Имелась ввиду обработка System.OverflowException в том случае, при отсутствии падения программы по причине System.StackOverflowException.
Друзья, речь, разумеется, не о факториале. Просто обнаружили, что не можем вообще обработать StackOverflowException. А пример про плохой факториал - это просто самое простое, что взято для иллюстрации.
И поэтому в PascalABC.NЕТ надо срочно притащить checked ?
А вот я обнаружил у языка (на мой взгляд, конечно) куда более существенный недостаток: он не умеет по утрам в постель кофе подавать! Как жить после этого - уме не приложу!
Ну, такое легче искать тут и там. Вот если не можете найти для C# - значит это может быть ошибка паскаля, но в данном случае по этому поводу полно инфы.