Funções recursivas: pra aprender recursividade, tem que saber recursividade

O título desse artigo em C pode parecer estranho, à primeira vista, mas ao fim do tutorial você entenderá essa ‘piada interna’ entre os programadores.

Neste tutorial de nossa apostila de C, vamos ensinar uma importante técnica: a recursão.

Recursividade em C

Uma função que é dita recursiva é aquela que invoca ela mesma.
Já explicamos, e demos exemplos, que é possível, recomendável e normal que uma função invoque outra.

Porém também é possível que uma função chame ela mesma, mas é preciso um cuidado especial para não cairmos em um looping infinito.

Geralmente, para que uma função não fique invocando ela mesma indefinidamente, devemos fazer umas alterações no argumento, ao invocar novamente a função ao passo que devemos definir, na função, testes condicionais sobre o parâmetro para saber onde devemos parar de invocar a função.

Ok, a equipe do curso C Progressivo assume: essa explicação é realmente complicada e todos sentiram dificuldade a primeira vez que a leram.

Mas, como de costume, vamos apresentar diversos exemplos de códigos, bem comentados, para que você possa entender melhor isso na prática.


Exemplo de código usando Recursão

Crie um programa em C que peça um número inteiro ao usuário e retorne a soma de todos os números de 1 até o número que o usuário introduziu ou seja: 1 + 2 + 3 + ... + n
Utilize recursividade.

Vamos criar uma função soma(int n).
Se n=5, essa função deve retornar: soma(5) = 5 + 4 + 3 + 2 + 1
Se n=4, essa função deve retornar: soma(4) = 4 + 3 + 2 + 1
Se n=3, essa função deve retornar: soma(3) = 3 + 2 + 1

E assim por diante. Porém, para fazermos uso da brilhante idéia matemática da recursividade, temos que notar padrões.
Veja que:
soma(5) = 5 + 4 + 3 + 2 +1 = 5 + soma(4)

O mesmo para:
soma(4) = 4 + 3 + 2 + 1 = 4 + soma(3)

Ou seja, temos a fórmula geral:
soma(n) = n + soma(n-1)
Concorda?

Ou seja:
soma(n) = n + soma(n-1) = n + (n-1) + soma(n-2) = n + (n-1) + (n-2) + soma(n-3)...

E onde essa soma para? Para quando o último elemento dessa soma for 1.
Então:
soma(n) = n +(n-1) + (n-2) + (n-3) + .... + 1

Agora vamos traduzir essa fórmula em termos de programação.
A função recebe um número, e a primeira coisa que ela deve fazer é ver se esse valor é 1.
Se for, deve retornar 1, afinal:
soma(1) = 1

E se não for 1, deve retornar:
n + soma(n-1)

Isso é feito da uma maneira muito simples, através de um simples teste condicional do tipo IF ELSE.
Veja como ficou nosso código em C:

#include <stdio.h>
 
int soma(int n)
{
    if(n == 1)
        return 1;
    else
        return ( n + soma(n-1) );
}
 
int main()
{
    int n;
    printf("Digite um inteiro positivo: ");
    scanf("%d", &n);
 
    printf("Soma: %d\n", soma(n));
}


Exemplo de código usando recursão em C

Crie um programa que calcule o fatorial de um número fornecido pelo usuário através da recursividade.
O fatorial de ‘n’ é representado por n!, onde:
n! = n * (n-1) * (n-2)*..1

O raciocínio desse exemplo é análogo ao do exemplo anterior, porém, vamos usar a multiplicação ao invés da soma.
Antes de resolvermos, vamos ver a idéia matemática por trás do fatorial.

Como dissemos na questão, para n=5:
5! = 5 * 4 * 3 * 2 * 1

Para n=4:
4! = 4 * 3 * 2 * 1

Para n=3:
3! = 3 * 2 * 1
E assim sucessivamente.
Porém, note que:
5! = 5 * 4 * 3 * 2 * 1 = 5 * 4!

E também:
4! = 4 * 3 * 2 * 1 = 4 * 3!

Podemos formular uma fórmula geral:
n! = n * (n-1)!

Abrindo esse produto, devemos parar somente quando o último elemento do produto for 1:
n! = n * (n-1)! = n * (n-1) * (n-2)! = n * (n-1) * (n-2) * ... * 1

Para programar isso, criamos uma função fatorial(int n) que retorna 1 se for passado 1 como argumento (pois fatorial(1) = 1) e caso o argumento seja maior que 1:
fatorial(n) = n * fatorial(n-1)

Isso, assim como no exemplo passado, e na maioria das funções usando a idéia de recursividade, é resolvido com um simples teste condicional IF ELSE.
Veja como ficou nosso código em C que calcula o fatorial:
#include <stdio.h>

int fatorial(int n)
{
    if(n == 1)
        return 1;
    else
        return ( n * fatorial(n-1) );
}

int main()
{
    int n;
    printf("Digite um inteiro positivo: ");
    scanf("%d", &n);

    printf("%d! = %d\n", n, fatorial(n));
}

Ou seja, pra calcular a função soma() é preciso usar a função soma().
Pra calcular o fatorial com a função fatorial() é preciso usar a função fatorial().
Entendeu agora o nome dessa lição?

40 comentários:

  1. Essa recursividade já tava me dando dor de cabeça. Esse site me clareou a idéia sobre o assunto.
    Vlw

    ResponderExcluir
  2. Olá amigo(a), que bom que te ajudou!

    Quem estudar e não entender algo de algum tutorial, basta comentar que tentaremos explicar melhor.

    ResponderExcluir
  3. Seu código está ok, só falta validar se o número é igual a zero pra não cair em loop infinito.

    ResponderExcluir
  4. Olá Willian,

    No primeiro exemplo vamos calcular a soma de "1+2+3+,,,+n" então estamos pressupondo que n é positivo, e ele nunca vai chegar a 0 (quando chega em 1, termina a recursão).

    No exemplo 2, idem, visto que não existe fatorial de número negativo.

    Concorda?

    ResponderExcluir
    Respostas
    1. Na verdade tem como você fazer da seguinte maneira existe fatorial de 0! =1 então ficaria assim :

      If(n ==o)
      return 1;
      Else
      return n*fatorial (n-1);

      Ou seja , vai pegar partir de zero acho que assim e o limite do fatorial !!!

      Excluir
  5. Vamos pensar que zero não é negativo nem positivo, no exemplo 1 se n>0 tudo bem porque ele vai para no if que valida se n=1, mas se a entrada para n for zero ai vai entrar em loop, isso se consider que 0 é não negativo.
    No exemplo 2, na matemática 0!=1, na então acho necessário fazer esta validação.

    ResponderExcluir
  6. Então, mas ao dizer que vamos somar de 1 até n e que n!=n*(n-1)*(n-2)*...*1 já estamos pressupondo que estamos esperando uma entrada que vai ser n>0. Ambos não são para caso de n<=0, embora possam ser alterados para isso.

    Há várias maneiras de colocar o programa em loop infinito (colocando qualquer número negativo) ou mesmo dar um crash, colocando uma letra ou outro símbolo, ou um número fora do range dos inteiros, um float, etc etc, levando a inúmeros testes de validação para deixar a aplicação bem robusta, mas esse rigor não é o propósito do tutorial.

    ResponderExcluir
  7. Esse post foi de grande valia para mim. Muito obrigado.

    ResponderExcluir
  8. Bacana de mais, clareza em seus comentarios.Valeu

    ResponderExcluir
  9. Porq não foi preciso um laço de repetição para verificar o fatorial?

    ResponderExcluir
  10. Willian Rojas está correto. Mesmo pedindo um inteiro positivo, você está deixando de lado o caso mais fundamental do fatorial, que é o zero. Se algum estudante olhar seu código, vai achar que não existe fatorial de zero. Não custa nada colocar um if(n==1 || n==0). Não vai deixar menos claro sua explicação e não vai atrapalhar nenhum estudante desavisado.

    ResponderExcluir
  11. Muito bom!! Poderiam colocar mais exemplos..

    ResponderExcluir
  12. Gostei da maneira que você está ajudando ambos entenderem sobre essa função . Mais você nao tem tipo , uns videos aulas para link para gente ?
    Porque a prof nao soube explicar direito esse assunto e semana que vem teremos Prova..
    #Focotira10naprovak
    Sou Academico: Ciência da Computação.

    ResponderExcluir
  13. Excelente explicação.
    Como eu poderia aplicar os cálculos recursivos de multiplicação em uma Estrutura de n Produtos, cada qual com sua composição de Insumos, que por sua vez também são compostos, até se chegar as Matérias-Primas?
    Vocês tem alguma dica?

    Grato
    Haroldo

    ResponderExcluir
  14. Amigo, não sei ao certo mas o código que você citou não funciona, retorna sempre 1

    #include

    int fatorial(int n)
    {
    if(n == 1)
    return 1;
    else
    return ( n * fatorial(n-1) );
    }

    int main()
    {
    int n;
    printf("Digite um inteiro positivo: ");
    scanf("%d", &n);

    printf("%d! = %d\n", n, fatorial(n));
    }
    fabiano_jr1984@hotmail.com

    ResponderExcluir
  15. Essa recursividade só serve para isso ou tem outras aplicações??

    ResponderExcluir
  16. O Código mais adequado seria esse,com certificação de não digitação de números menores que zero, e o fatorial de zero, que é 1.




    int fatorial(int n)
    {
    if(n == 1 || n == 0)
    return 1;
    else
    return(n * fatorial(n-1));
    }

    int main()
    {
    int n;

    do
    {
    printf("Digite um inteiro positivo: ");
    scanf("%d", &n);
    } while(n<0);


    printf("%d! = %d\n", n, fatorial(n));

    return 0;
    }

    ResponderExcluir
  17. Oi!
    Primeiramente gostaria de agradecer; a sua gentileza e paciência de teres partilhado esse seu conhecimento connosco. eu sou estudante da faculdade ciências da universidade Agostinho Neto. podes não crer mais ela é uma das melhores de Angola(computação), mas o meu professor de imperativa não consegue transmitir esses conhecimentos computacionais, e o pessoal já notou nele muita falta de pedagogia. por isso suas dicas foram muito bem esclarecedoras: obrigado mais uma vez e um abraço de Angola.

    ResponderExcluir
  18. Parabéns pelo ótimo conteúdo. Ajudou bastante.

    ResponderExcluir
  19. Não entendi o porquê do return 1, em meu programa, tanto o de soma como o de fatorial não funcionaram sem o return 1, mesmo o valor passado sendo diferente de 1.

    ResponderExcluir
  20. Parabéns pela explicação. Simples e efetiva! :)

    ResponderExcluir
  21. Muito obrigada, foi devido a sua explicacão que consegui entender a questão da recursividade. Até então eu estava somente copiando o código.

    Muito obrigada!! Você é fera!! Parabéns!

    ResponderExcluir
  22. Muito obrigada, foi devido a sua explicacão que consegui entender a questão da recursividade. Até então eu estava somente copiando o código.

    Muito obrigada!! Você é fera!! Parabéns!

    ResponderExcluir
  23. Bom dia moçada.

    Fiquei com a seguinte dúvida:

    Digamos que no main eu utilize a formula do fatorial assim: Fatorial(4);

    Entao no desvio da condição, vai para o else:

    return n * fatorial(n-1);

    Ai eu pergunto: em que momento o algoritmo multiplicou o 3 * 2 * 1?
    Foi assim que me enrrolei :S

    ResponderExcluir
  24. Bom dia:

    Se no main, eu utilizar fatorial(4);
    O algoritmo vai entender assim: return n * fatorial(n-1);

    ou seja...

    4 * fatorial(3);

    Mas, em que momento do algoritmo ele multiplica 3 * 2 * 1 ?

    ResponderExcluir
  25. Olá! Parabéns me ajudaram muito a esclarecer a dúvida de como executar este tipo de programa.
    Valeu.

    ResponderExcluir
  26. Voce consegue fazer uma função recursiva em c para logaritmo?

    ResponderExcluir
  27. Gostaria de saber o nome de quem escreveu esse artigo para usar como referência no meu trabalho

    ResponderExcluir
  28. Na verdade você pode incluir o 0 no fatorial, pois fatorial de 0 é 1. Então nesse caso, se o usuário entrar com 0, o resultado será 1.

    ResponderExcluir
  29. Excelente Texto, muito recomendado para tirar as dúvidas de quem está começando a programar em c euheuehue

    ResponderExcluir
  30. Olá, alguém poderia me ajudar no seguinte problema?
    Resolva a seguinte função recursiva escrita na linguagem C que devolve a soma de todos os elementos de um vetor, onde size é o tamanho do vetor. Assuma que os parâmetros passados ao registrador "sum" são: endereço do vetor no registrador $a0 e o valor size no registrador $a1. Os elementos do vetor são inteiros de 32 bits (words). Lembre-se de utilizar a pilha.

    int sum( int vetor[], int size) {
    if ( size ==0 )
    return 0 ;
    else
    return sum ( vetor, size - 1 ) + vetor[ size - 1 ] ;
    }

    ResponderExcluir
  31. nt soma( int* vet, int n);



    if (n==1)
    {

    return 1;

    else
    return (n+(n-1));

    }

    int main()
    {
    int n;
    cout<<"Digite um inteiro positivo: ";
    cin>>n;
    cout<< "soma:"<< int soma (int* vet);
    }

    ResponderExcluir
  32. Olha, eu comecei a ver Recursividade a 8diaas atras e ja estava a aquecer !! Obgd pelo clareamento da materia

    ResponderExcluir
  33. achei deveras impressionante a forma como percebi este codigo, nao sei se é por ser bom em programacion ou porque é mesmo facil

    ResponderExcluir
  34. Luis Gouveia de Santo António29 de outubro de 2021 às 06:35

    está muito porreiro

    ResponderExcluir
  35. Que emoção finalmente entender a recursividade depois de dois dias quebrando a cabeça. Não tenho nem como agradecer pela ajuda!

    ResponderExcluir

É quase impossível criar centenas de páginas voltadas para programação C e não cometer algum erro.

- Se notar algum conceito, letra ou trecho de código errado, deixe sua correção

- Se perceber uma maneira melhor ou mais eficiente de fazer algo, deixe sua ideia

- Se algo não ficar claro ou for confuso, nos avise

Aos poucos vamos aumentando e melhorando a qualidade de nosso material, e para isso contamos com sua ajuda.