Вы также можете использовать метод compareTo()
для сравнения двух строк. Если результат compareTo равен 0, то две строки равны, в противном случае сравниваемые строки не равны.
==
сравнивает ссылки и не сравнивает фактические строки. Если вы создали каждую строку, используя new String(somestring).intern()
, вы можете использовать оператор ==
для сравнения двух строк, в противном случае могут использоваться только методы equals () или compareTo.
Вы возвращаетесь на глубину 4400, что вызывает проблемы. Также в этом нет необходимости, поскольку вы можете реализовать тот же алгоритм с помощью цикла:
while (n >= m) n -= m ;
return n ;
Если рекурсия слишком глубокая, программе не хватает памяти стека. Это называется переполнением стека.
int modulo(int n, int m)
{
if (n < m) return n;
else return modulo(n - m, m);
}
Например, modulo(1000000, 2)
вызывает modulo(999998, 2)
, что вызывает modulo(999996, 2)
, и так далее, пока в конце modulo(0, 2)
не будет 500001 активных функций modulo
в стеке. Два целых числа, адрес возврата и указатель кадра, должны занимать не менее 16 байт на вызов функции в любой разумной системе. Всего 8 мегабайт стекового пространства, что обычно превышает максимальный размер стека.
Каждый вызов функции должен ждать результатов следующей функции, пока он не завершит свой расчет и не вернется. До его возвращения в стеке должны были храниться все переменные, параметры и адрес возврата. Адрес возврата - это место в программе, где программа должна возобновить работу после оператора return
.
Эти вызовы заполняют стек до тех пор, пока не будет достигнут его максимальный предел и программа не завершится.
В некоторых случаях компилятор может преобразовать рекурсию в цикл. В этом случае, поскольку рекурсия находится в операторе return
, она может просто goto
перейти к началу функции, вообще не выполняя вызов. Это называется оптимизация хвостового вызова :
int modulo(int n, int m)
{
start:
if (n < m) return n;
else {
n -= m;
goto start;
}
}
Если бы вы включили оптимизацию (-O2 в clang или G ++ или режим выпуска в Visual C ++), не было бы сбоя, так как компилятор создал бы цикл вместо рекурсии. Чтобы избежать сбоя, просто включите оптимизацию.
Обратите внимание, что компилятор не обязан оптимизировать это, и не всегда может. Вот почему не рекомендуется иметь такую глубокую рекурсию.