#c #c #segmentation-fault
#c #c #ошибка сегментации
Вопрос:
Я новичок в концепции рекурсии. Я хочу написать рекурсивную функцию, которая принимает значение с плавающей точкой и целое число в качестве аргумента и вызывает ее рекурсивно таким образом, чтобы значение с плавающей точкой оставалось постоянным, а целочисленное значение изменялось
Я пишу следующий код:
#include <stdio.h>
float sum(float f, int k)
{
static float c;
c = f - k;
c = sum(f, k - 1);
return c;
}
int main()
{
float f, g = 10.00;
int i = 5;
f = sum(g, i);
printf("the sum of integer and float = %f", f);
}
Когда я ее компилирую, она не показывает ошибок, но когда я запускаю программу, она показывает ошибку сегментации.
Мой вопрос заключается в следующем:
- что не так с кодом?
- почему отображается ошибка сегментации?
- как использовать рекурсию в функции, которая имеет более одного аргумента?
Пожалуйста, объясните мне на каком-нибудь примере рекурсивной функции, которая имеет два аргумента.
Комментарии:
1. это утверждение c = sum(f, k — 1); должно быть c = sum(f, k — 1);. Если речь идет о логике.
2. нет условия завершения
Ответ №1:
Код неверен, потому что он никогда не может завершиться (я предполагаю, что он завершается ошибкой stackoverflow).
Для рекурсии вам нужны две вещи
- Базовый вариант
- Рекурсивный вариант, который движется к базовому варианту
Похоже, у вас есть только вторая. Я подозреваю, что сумма должна возвращаться, когда k
равно нулю. Надеюсь, что-то подобное имеет смысл:
float sum(float f, int k) {
if (k <= 0) {
// The base case
return f;
} else {
// The recursive case. This does one step of the work
// and moves towards the base case
return 1 sum(f, k - 1);
}
}
Комментарии:
1. Лучше использовать хвостовую рекурсию, чтобы размер стека оставался постоянным.
2. Да, если ваш язык поддерживает хвостовую рекурсию, тогда я согласен. Что касается объяснения вещей, я думаю, что это обсуждение, которое начинается после получения рекурсии.
Ответ №2:
Ваша рекурсия не имеет базового (нерекурсивного), завершающего регистра.
Каждый вызов sum
вызывает рекурсивный вызов к самому себе, это продолжается до тех пор, пока ваш stackoverflows не завершится, что приведет к ошибке seg.
Ответ №3:
Рекурсия никогда не останавливается, и в конечном итоге у вас заканчивается стек. Вам нужно решить, когда пришло время остановить рекурсию. например, если k
равно 0, вы не вызываете sum
повторно, а завершаете с return
.
float sum(float f ,int k)
{
static float c;
if (k > 0)
{
c=f-k; /// <<< why is this here? you ignore the value and overwrite it in the next step.
c=sum(f,k-1);
}
return c;
}
Конечно, есть дополнительные проблемы: c
статичность может быть проблемой, которая повлияет на правильность вычисления, а также место, которое я отметил, выглядит подозрительно, потому что вы теряете значение и перезаписываете его при последующем вызове sum
.
Ответ №4:
Как насчет этого?
#include <stdio.h>
float sum(float f, int k, float c) {
if (k == 0)
return c;
sum(f, k - 1, f - k);
}
Ответ №5:
Первое, что я вижу, это то, что ваша рекурсия не имеет завершения. Это будет продолжаться вечно. Возможно, вы хотите:
float sum(float f ,int k)
{
static float c;
c=f-k;
if (k != 0)
c=sum(f,k-1);
return c;
}
Так что, когда k равно нулю, рекурсия останавливается. У вас произошло переполнение стека.
Ответ №6:
Когда вы выполняете рекурсию, вам нужен статус для ее завершения.
Итак, ваш код с изменениями:
#include <stdio.h>
float sum(float f, int k)
{
if(k == 0) return f;
return 1 sum(f,k-1);
}
int main()
{
float f, g = 10.00;
int i = 5;
f = sum(g, i);
printf("the sum of integer and float = %f", f);
}
С этим кодом и вашим примером f = 10.00 и i = 5
Call sum(10.0, 5)
return 1 sum(10.0, 4)
1 sum(10.0, 3)
1 sum(10.0, 2)
1 sum(10.0, 1)
1 sum(10.0, 0)
10
1 10 = 11
1 11 = 12
1 12 = 13
1 13 = 14
1 14 = 15
return 15;
Ответ №7:
Я не понимаю, для чего предназначена функция «sum». Предполагается ли добавление f и k? В этом случае рекурсии не происходит; вам следует просто добавить f и k: return f k
.
Но чтобы попытаться ответить на ваши вопросы:
- Нет базового варианта. Это является причиной бесконечной рекурсии. Каждой рекурсивной функции необходим базовый вариант, который является условием, при котором она не выполняет рекурсию. Ваша функция повторяется независимо ни от чего; следовательно, она всегда будет повторяться вечно.
- Когда рекурсия прерывается, это обычно происходит из-за переполнения стека (без каламбура); это означает, что вы повторяетесь вечно и в конечном итоге у вас заканчивается пространство.
- Вы можете использовать рекурсию в функции с более чем одним аргументом, точно так же, как и в любой другой функции. Просто вызовите ее с любыми новыми значениями для следующей итерации.
Обратите внимание, что у вас часто есть «постоянное» значение, которое не изменяется во время рекурсии. Для этого вы просто передаете значение без изменений при рекурсивном вызове, поэтому одно и то же значение доступно на каждом шаге.