проблема с программой рекурсии c

#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. что не так с кодом?
  2. почему отображается ошибка сегментации?
  3. как использовать рекурсию в функции, которая имеет более одного аргумента?

Пожалуйста, объясните мне на каком-нибудь примере рекурсивной функции, которая имеет два аргумента.

Комментарии:

1. это утверждение c = sum(f, k — 1); должно быть c = sum(f, k — 1);. Если речь идет о логике.

2. нет условия завершения

Ответ №1:

Код неверен, потому что он никогда не может завершиться (я предполагаю, что он завершается ошибкой stackoverflow).

Для рекурсии вам нужны две вещи

  1. Базовый вариант
  2. Рекурсивный вариант, который движется к базовому варианту

Похоже, у вас есть только вторая. Я подозреваю, что сумма должна возвращаться, когда 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 .

Но чтобы попытаться ответить на ваши вопросы:

  1. Нет базового варианта. Это является причиной бесконечной рекурсии. Каждой рекурсивной функции необходим базовый вариант, который является условием, при котором она не выполняет рекурсию. Ваша функция повторяется независимо ни от чего; следовательно, она всегда будет повторяться вечно.
  2. Когда рекурсия прерывается, это обычно происходит из-за переполнения стека (без каламбура); это означает, что вы повторяетесь вечно и в конечном итоге у вас заканчивается пространство.
  3. Вы можете использовать рекурсию в функции с более чем одним аргументом, точно так же, как и в любой другой функции. Просто вызовите ее с любыми новыми значениями для следующей итерации.

Обратите внимание, что у вас часто есть «постоянное» значение, которое не изменяется во время рекурсии. Для этого вы просто передаете значение без изменений при рекурсивном вызове, поэтому одно и то же значение доступно на каждом шаге.