Lenguaje de programación C, compilado con gcc, terminal bash en WSL
He escrito una función recursiva, para encontrar el número más bajo en una matriz, que funciona bien.
/*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*/ }
El único problema es que no debería funcionar, porque no devuelve "min" a la persona que llama ...
int main()
{
//Var
int array[N] = {10, 2, 5, 1, 7};
printf("Min: %d\n", minimo(array, 0));
}
Mi preocupación es en realidad un problema, pero no en mi máquina en la que la función funciona tan bien como está; es un problema en las computadoras portátiles e IDE de mis amigos, intenté copiar a XCode en la Macbook de un amigo y no funcionaría si la línea "return min"; no se agregó al final de la función.
Entre la línea 15-16 tengo que agregar return min;
/*15*/ }
return min;
/*16*/ }
Mis preguntas para usted son las siguientes:
- ¿Cómo puede una función devolver una variable automáticamente ?
- ¿Es posible que devuelva la única variable que creé (static int min)?
- ¿O es un "problema" relacionado con el atributo estático que tiene la variable?
- ¿Tiene algo que ver con la naturaleza de la función ( recursiva )?
Esta es mi primera publicación, por favor sea amable si no cumplo con alguna regla del foro.
main
devuelve su función.main
sino del valor de retorno "automático" de una función en una implementación específica.C
estándar particular devuelve cero en ausencia de una declaración de devolución.-Wall
interruptor y ver qué le dice el compilador.Respuestas:
Ejemplo típico de comportamiento indefinido . Funciona en una máquina pero no en otra. Funciona de día pero no de noche. Funciona con un compilador pero no con otro. Cuando invoca un comportamiento indefinido, el estándar C no impone requisitos sobre cómo debe comportarse el código.
C11 estándar 6.9.1.12
En su código, eso es precisamente lo que sucede. Invoca un comportamiento indefinido cuando intenta imprimir el valor de retorno.
Al contrario de lo que muchos creen, está completamente permitido omitir la declaración de devolución en una función no nula. Solo se convierte en un comportamiento indefinido si intenta utilizar el valor de retorno inexistente.
Para evitar esto, compile siempre con al menos
-Wall -Wextra
.fuente
-Werror
!-Werror
SO, recibe una pregunta con "¿Por qué esto no se compila?" y sin ella "¿Por qué esto se comporta extraño?" Si bien estoy de acuerdo en que ese parámetro es algo bueno, se pierde el objetivo.-Werror
evita preguntas SO innecesarias como esta, porque el usuario se ve obligado a preocuparse por las advertencias cuando no tiene un ejecutable roto para ejecutar :-)Sigue el protocolo. Sabe que el retorno de la función debe encontrar el valor devuelto en alguna ubicación y un explícito
return
de esa función llenará esa ubicación. Si no llamareturn
, se conservará algún valor aleatorio en la ubicación dada.No, no está definido lo que devuelve. Puede ser lo que sea.
Nuevamente, lo que devuelve no está definido.
Si y no. Si la función se define como externa, el valor devuelto sigue otro protocolo como en el caso de las funciones estáticas.
Puede suceder cualquier cosa en el código final, el lenguaje C no impone la forma de implementar una función, ya sea recursiva o no. Por ejemplo, en caso de que la función sea recursiva y pueda calcularse previamente, solo el valor final puede reemplazarse en el lugar de la llamada. Esto también es correcto ya que el resultado final del programa es el resultado esperado, conforme a la semántica operativa que define C en
ISO9899
.Cito del documento oficial:
También puede reemplazar una llamada con el valor de esa llamada y esto es correcto.
Entonces, en todas sus preguntas, la respuesta es un comportamiento indefinido .
fuente
Sucede por casualidad, la
min
variable está en el registro de retorno correcto para el ABI.Creo que está más relacionado con que se haya utilizado justo antes de la salida de la función, pero supongo que aquí: este no es un comportamiento definido en lenguaje C, y funcionó por casualidad.
Como se trataba de un comportamiento casual, podría serlo o no. La diferencia entre aleatorio y determinista es que tiene tantas variables que deja de explicar.
fuente
Supongo que definiste N en alguna parte (probablemente N = 5 en tu caso).
La mayoría de los compiladores agrega automáticamente la declaración "return 0" si falta la declaración return.* Ver comentarios para más información. En realidad es un comportamiento indefinido *
En su función recursiva, es mejor pasar la longitud restante de la matriz y detenerse cuando alcanza n == 0.
Evite mirar variables globales o define funciones internas.
(se requiere otra modificación)
En realidad, debe conocer la longitud de la matriz solo en la función principal, así que llámela como:
fuente
main()
en las implementaciones de C99 (o posterior) (dondereturn 0;
se agrega a en ausencia de una declaración de retorno anterior) , la fallareturn
es UB .C89
. Y eso es un mínimo que puedo obtener hoy.