Retorna sem um comando "return"


8

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:

  1. Como uma função pode retornar uma variável automaticamente ?
  2. É possível que ele retorne a única variável que eu criei (static int min)?
  3. Ou é um "problema" relacionado ao atributo estático que a variável possui?
  4. 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.


Leia a pergunta SO: stackoverflow.com/q/204476/8339821 e as respostas. Isso o levará ao ponto em que sua mainfunção retorna.
yvw 14/02

À primeira vista, parece algo específico da WSL, não específico do gcc. Parece que a WSL "pensa" automaticamente em você e corrige o código por conta própria.
RobertS apoia Monica Cellio

@ ЯрославМашко Isso é uma coisa completamente diferente e não tem nada a ver com esta pergunta. O problema não é sobre o valor de retorno, mainmas sobre o valor de retorno "automático" de uma função em uma implementação específica.
RobertS apoia Monica Cellio em 14/02

@RobertSsupportsMonicaCellio Sim, você está certo. Li a pergunta novamente e percebi que o SO quer saber o que sua função realmente retorna. Eu pensei que ele de alguma forma erra o retorno do main. Em seguida, esta resposta fornece informações completas sobre o assunto: stackoverflow.com/a/1610454/8339821 . O ponto principal é que um determinado Cpadrão retorna zero na ausência de uma declaração de retorno.
yvw 14/02

Você deve compilar seu arquivo com uma -Wallopção e ver o que o compilador diz.
yvw 14/02

Respostas:


5

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.

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

Se o} que encerra uma função for alcançado e o valor da chamada de função for usado pelo chamador, o comportamento será indefinido.

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.


E não esqueça -Werror!
Jonathon Reinhart

@ JonathonReinhart Bem, esse é o tipo de discussão que requer cerveja. :)
klutt 14/02

1
@ JonathonReinhart O importante é realmente cuidar dos avisos. Se o codificador não se importar e estiver usando o -WerrorSO, 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.
klutt 14/02

1
Meu sentimento é que -Werrorevita 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 :-)
Jonathon Reinhart

2
Talvez o GCC deva, por padrão, simplesmente apresentar mensagens de erro no formato HTML com o tema Stack Overflow e resultados de pesquisa incorporados
Jonathon Reinhart

2

Como uma função pode retornar uma variável automaticamente?

Segue o protocolo. Ele sabe que o retorno da função deve encontrar o valor retornado em algum local e um explícito returndessa função preencherá esse local. Se você não ligar return, algum valor aleatório será preservado no local especificado.

É possível que ele retorne a única variável que eu criei (static int min)?

Não, é indefinido o que retorna. Pode ser o que for.

Ou é um "problema" relacionado ao atributo estático que a variável possui?

Novamente, o que ele retorna é indefinido.

Tem algo a ver com a natureza da função (recursiva)?

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:

4 Na máquina abstrata, todas as expressões são avaliadas conforme especificado pela semântica. Uma implementação real não precisa avaliar parte de uma expressão se puder deduzir que seu valor não é usado e que nenhum efeito colateral necessário é produzido (incluindo os causados ​​pela chamada de uma função ou pelo acesso a um objeto volátil).

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 .


1

Como uma função pode retornar uma variável automaticamente?

Acontece por acaso, a minvariável está no registro de retorno correto para o ABI.

É possível que ele retorne a única variável que eu criei (static int min)?

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.

Ou é um "problema" relacionado ao atributo estático que a variável possui?

Tem algo a ver com a natureza da função (recursiva)?

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.


-3

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.

int minimo(int array[], int n)
{
  ...
  if (n == 0)
  ...
            min = minimo(array, n-1);
  ...
}

(é necessária outra modificação)

Na verdade, você deve saber o comprimento da matriz apenas na função principal, então chame-a como:

printf("Min: %d\n", minimo(array, N));

5
Não! Exceto main()nas implementações C99 (ou posteriores) (em que a return 0;é adicionada na ausência de uma declaração de retorno anterior) , a falha returné UB .
pmg 14/02

@pmg em algum lugar no SO eu li que a redação se resume a C89. E isso é o mínimo que posso obter hoje.
yvw 14/02

@ :РославМашко: C89 não menciona o valor de retorno padrão; C99 (e da mesma forma em C11 ): "... alcançar o} que encerra a função principal retorna um valor de 0." (ênfase é minha)
pmg 14/02
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.