Linguagem de programação C, compilada com gcc, terminal bash no WSL
Eu escrevi uma função recursiva, para encontrar o número mais baixo em uma matriz, que funciona muito bem.
/*01*/ int minimo(int array[], int n)
/*02*/ {
/*03*/ static int min = 0;
/*04*/
/*05*/ if (n == N)
/*06*/ {
/*07*/ return array[n-1];
/*08*/ }
/*09*/ else
/*10*/ {
/*11*/ min = minimo(array, n+1);
/*12*/ if(array[n]<min){
/*13*/ min = array[n];
/*14*/ }
/*15*/ }
/*16*/ }
O único problema é que não deve funcionar, porque não retorna "min" ao chamador ...
int main()
{
//Var
int array[N] = {10, 2, 5, 1, 7};
printf("Min: %d\n", minimo(array, 0));
}
Minha preocupação é realmente um problema, mas não na minha máquina na qual a função funciona tão bem quanto é; é um problema nos laptops e IDEs dos meus amigos, tentei copiar para o XCode no Macbook de um amigo e não funcionaria se a linha "return min"; não foi adicionado no final da função.
Entre a linha 15-16 eu tenho que adicionar return min;
/*15*/ }
return min;
/*16*/ }
Minhas perguntas para você são as seguintes:
- Como uma função pode retornar uma variável automaticamente ?
- É possível que ele retorne a única variável que eu criei (static int min)?
- Ou é um "problema" relacionado ao atributo estático que a variável possui?
- Tem algo a ver com a natureza da função ( recursiva )?
Este é o meu primeiro post, por favor, seja gentil se estou violando alguma regra do fórum.
main
função retorna.main
mas sobre o valor de retorno "automático" de uma função em uma implementação específica.C
padrão retorna zero na ausência de uma declaração de retorno.-Wall
opção e ver o que o compilador diz.Respostas:
Exemplo típico de comportamento indefinido . Funciona em uma máquina, mas não em outra. Funciona durante o dia, mas não durante a noite. Funciona com um compilador, mas não com outro. Quando você invoca um comportamento indefinido, o padrão C não impõe requisitos sobre como o código deve se comportar.
Norma C11 6.9.1.12
No seu código, é exatamente isso que acontece. Você invoca um comportamento indefinido ao tentar imprimir o valor de retorno.
Ao contrário do que muitos acreditam, é completamente permitido omitir a declaração de retorno em uma função não nula. Ele só se torna um comportamento indefinido se você tentar usar o valor de retorno inexistente.
Para evitar isso, sempre compile com pelo menos
-Wall -Wextra
.fonte
-Werror
!-Werror
SO, a pergunta "Por que isso não é compilado?" e sem ele "Por que isso se comporta de maneira estranha?" Embora eu concorde que esse parâmetro seja uma coisa boa, ele erra o alvo.-Werror
evita questões desnecessárias de SO como esta, porque o usuário é forçado a se preocupar com os avisos quando não tem um executável quebrado para executar :-)Segue o protocolo. Ele sabe que o retorno da função deve encontrar o valor retornado em algum local e um explícito
return
dessa função preencherá esse local. Se você não ligarreturn
, algum valor aleatório será preservado no local especificado.Não, é indefinido o que retorna. Pode ser o que for.
Novamente, o que ele retorna é indefinido.
Sim e não. Se a função for definida como externa, o valor retornado segue outro protocolo, como no caso de funções estáticas.
Pode acontecer qualquer coisa no código final, a linguagem C não impõe a maneira de implementar uma função, seja recursiva ou não. Por exemplo, se a função for recursiva e puder ser pré-computada, apenas o valor final poderá ser substituído no local da chamada. Isso também é correto na hora em que o resultado final do programa é o resultado esperado, em conformidade com a semântica operacional que define C in
ISO9899
.Cito o documento oficial:
Também pode substituir uma chamada pelo valor dessa chamada e isso está correto.
Portanto, em todas as suas perguntas, a resposta é um comportamento indefinido .
fonte
Acontece por acaso, a
min
variável está no registro de retorno correto para o ABI.Eu acho que está mais relacionado ao fato de ter sido usado logo antes da saída da função, mas acho que aqui: esse não é um comportamento definido na linguagem C e funcionou por acaso.
Como esse era um comportamento casual, poderia ser ou não. A diferença entre aleatório e determinístico é que você tem tantas variáveis que desiste de explicar.
fonte
Suponho que você definiu N em algum lugar (provavelmente N = 5 no seu caso).
A maioria dos compiladores adiciona automaticamente a declaração "return 0" se a declaração de retorno estiver ausente.* Veja os comentários para mais informações. Na verdade, é um comportamento indefinido *
Na sua função recursiva, é melhor passar o comprimento restante da matriz e parar quando você atingir n == 0.
Evite examinar variáveis globais ou definir funções internas.
(é necessária outra modificação)
Na verdade, você deve saber o comprimento da matriz apenas na função principal, então chame-a como:
fonte
main()
nas implementações C99 (ou posteriores) (em que areturn 0;
é adicionada na ausência de uma declaração de retorno anterior) , a falhareturn
é UB .C89
. E isso é o mínimo que posso obter hoje.