HOWTO · C
Función MIN y MAX en C
Se pueden usar macros o bucles para implementar la función MIN y MAX en C.
En esta página
Para encontrar el menor o el mayor de dos valores en C, define una macro MIN o MAX, o escribe una función. C estándar no proporciona funciones generales MIN y MAX integradas. Para un arreglo, inicializa el resultado con su primer elemento y recorre los elementos restantes.
¿MIN y MAX vienen integradas en C?
La biblioteca estándar de C no define funciones generales MIN y MAX. Es habitual que un proyecto proporcione estos nombres como macros o funciones ordinarias. Cuando los argumentos tienen efectos secundarios, una función es más fácil de razonar; una macro sencilla puede ser concisa si los valores se evalúan de forma segura.
La directiva #define crea una macro del preprocesador. Cuando este encuentra una llamada a la macro, sustituye el texto de reemplazo antes de que el compilador procese el programa. En cambio, una llamada a una función ejecuta código compilado y sus argumentos se evalúan según las reglas de llamada de funciones de C.
Definir macros MIN y MAX para dos valores
Para dos expresiones enteras sin efectos secundarios, pon entre paréntesis cada parámetro y toda la expresión de reemplazo. Así se conserva la agrupación prevista cuando quien llama pasa una expresión como a + b.
#include <stdio.h>
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
int main(void) {
printf("Min = %d\n", MIN(0, 10));
printf("Max = %d\n", MAX(0, 10));
return 0;
}
Min = 0
Max = 10
El operador condicional ?: selecciona la expresión que sigue a ? cuando la comparación es verdadera y la que sigue a : en caso contrario. Los paréntesis controlan la precedencia, pero no evitan que una expresión se evalúe varias veces: en MIN(a, b), el argumento seleccionado vuelve a aparecer en el texto de reemplazo. Evita argumentos como i++ o llamadas a funciones que cambien el estado. Esta forma de macro es más adecuada para valores simples; si los argumentos pueden tener efectos secundarios, usa una función.
Usar una macro de GNU C para evaluar los argumentos una sola vez
GNU C admite expresiones de sentencia y typeof (escrito __typeof__ en este ejemplo). La macro siguiente guarda cada argumento en una variable temporal y luego compara esos valores. Cada expresión de argumento se evalúa una sola vez, en su inicializador. Se trata de una extensión de GNU C, por lo que no es portable a ISO C y puede requerir una opción del compilador que habilite las extensiones GNU.
#include <stdio.h>
#define MAX(x, y) \
({ \
__typeof__(x) _max_x = (x); \
__typeof__(y) _max_y = (y); \
_max_x > _max_y ? _max_x : _max_y; \
})
#define MIN(x, y) \
({ \
__typeof__(x) _min_x = (x); \
__typeof__(y) _min_y = (y); \
_min_x < _min_y ? _min_x : _min_y; \
})
int main(void) {
int a = 4;
int b = 9;
printf("Min = %d\n", MIN(a++, b));
printf("Max = %d\n", MAX(a, b));
return 0;
}
Min = 4
Max = 9
Este patrón es útil para expresiones escalares ordinarias cuyos tipos se pueden comparar con < o >. No es una función genérica para cualquier tipo: los tipos incompatibles, los punteros sin un orden significativo y los tipos que no admiten estos operadores requieren otro diseño. La expresión condicional también sigue las reglas habituales de conversión de tipos de C. Para escribir código portable, prefiere una función con tipos definidos o crea funciones separadas para los tipos que necesites admitir.
Encontrar el mínimo y el máximo de un arreglo
Para procesar un arreglo, conserva el mínimo y el máximo actuales y actualízalos mientras lo recorres. Inicializa ambos con el primer elemento para que el resultado se base en un valor real del arreglo. El ejemplo usa los mismos valores que el ejemplo original de arreglos y recorre el arreglo una sola vez.
#include <stdio.h>
#include <stddef.h>
void find_min_max(const int values[], size_t length, int *minimum, int *maximum) {
*minimum = values[0];
*maximum = values[0];
for (size_t i = 1; i < length; ++i) {
if (values[i] < *minimum) {
*minimum = values[i];
}
if (values[i] > *maximum) {
*maximum = values[i];
}
}
}
int main(void) {
int values[] = {6, 3, 15, 9, 10, 50, 99, 11};
size_t length = sizeof(values) / sizeof(values[0]);
int minimum;
int maximum;
find_min_max(values, length, &minimum, &maximum);
printf("Max number = %d\n", maximum);
printf("Min number = %d\n", minimum);
return 0;
}
Max number = 99
Min number = 3
Esta función requiere un arreglo no vacío y punteros válidos para los resultados. Quien la llama pasa la longitud porque un parámetro de arreglo se ajusta a un puntero; dentro de find_min_max, sizeof(values) mide el puntero, no el arreglo original. En este caso, sizeof permite calcular la cantidad de elementos en main, donde values todavía es un arreglo: divide su tamaño total entre el tamaño de un elemento.
Para datos de punto flotante, usa un tipo coherente para el arreglo, las variables del mínimo y el máximo, y los parámetros de la función. El especificador de conversión de printf debe coincidir con el tipo promovido del argumento; para un double, usa %f. Si la función debe aceptar varios tipos numéricos, escribe funciones con los tipos adecuados o diseña una abstracción con cuidado, en lugar de cambiar únicamente int por float.