HOWTO · C

MIN- und MAX-Funktion in C

Man kann Makros oder Schleifen verwenden, um die MIN- und MAX-Funktion in C zu implementieren.

Auf dieser Seite

Um in C den kleineren oder größeren von zwei Werten zu bestimmen, können Sie ein MIN- oder MAX-Makro definieren oder eine Funktion schreiben. Der C-Standard stellt keine allgemeinen eingebauten MIN- und MAX-Funktionen bereit. Bei einem Array initialisieren Sie das Ergebnis mit dem ersten Element und durchlaufen anschließend die übrigen Elemente.

Gibt es in C eingebaute MIN- und MAX-Funktionen?

Die C-Standardbibliothek definiert keine allgemeinen MIN- und MAX-Funktionen. Solche Namen werden häufig in einem Projekt als Makros oder gewöhnliche Funktionen bereitgestellt. Eine Funktion ist leichter nachvollziehbar, wenn Argumente Seiteneffekte haben; ein einfaches Makro kann für Werte, die sich gefahrlos auswerten lassen, eine knappe Lösung sein.

Die Direktive #define erstellt ein Präprozessormakro. Wenn der Präprozessor einen Makroaufruf erkennt, ersetzt er diesen durch den Ersetzungstext, bevor der Compiler das Programm verarbeitet. Ein Funktionsaufruf hingegen führt kompilierten Code aus; seine Argumente werden gemäß den Regeln für Funktionsaufrufe in C ausgewertet.

MIN- und MAX-Makros für zwei Werte definieren

Bei zwei Integer-Ausdrücken ohne Seiteneffekte sollten Sie jeden Parameter und den gesamten Ersetzungsausdruck in Klammern setzen. So bleibt die beabsichtigte Gruppierung erhalten, wenn ein Aufrufer einen Ausdruck wie a + b übergibt.

#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

Der bedingte Operator ?: wählt den Ausdruck nach ? aus, wenn der Vergleich wahr ist, andernfalls den Ausdruck nach :. Klammern berücksichtigen die Operatorrangfolge, verhindern aber keine mehrfache Auswertung: Bei MIN(a, b) erscheint das ausgewählte Argument erneut im Ersetzungstext. Vermeiden Sie Argumente wie i++ oder Funktionsaufrufe, die einen Zustand verändern. Diese Makroform eignet sich am besten für einfache Werte; wenn Argumente Seiteneffekte haben können, verwenden Sie eine Funktion.

Mit einem GNU-C-Makro Argumente einmal auswerten

GNU C unterstützt Statement Expressions und typeof (in diesem Beispiel als __typeof__ geschrieben). Das folgende Makro speichert jedes Argument in einer temporären Variable und vergleicht anschließend diese Werte. Jeder Argumentausdruck wird bei seiner Initialisierung einmal ausgewertet. Dies ist eine GNU-C-Erweiterung und daher nicht mit ISO C portabel; möglicherweise benötigen Sie eine Compileroption, die GNU-Erweiterungen aktiviert.

#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

Dieses Muster eignet sich für gewöhnliche skalare Ausdrücke, deren Typen sich mit < oder > vergleichen lassen. Es ist keine universelle, typsichere Funktion: Bei inkompatiblen Typen, Zeigern ohne sinnvolle Ordnung und Typen, die diese Operatoren nicht unterstützen, ist ein anderer Ansatz erforderlich. Auch für den bedingten Ausdruck gelten die üblichen Typumwandlungsregeln von C. Für portablen Code verwenden Sie besser eine Funktion mit festgelegtem Typ oder schreiben Sie separate Funktionen für die unterstützten Typen.

Minimum und Maximum in einem Array finden

Halten Sie bei einem Array das aktuelle Minimum und Maximum fest und aktualisieren Sie beide beim Durchlaufen der Elemente. Initialisieren Sie beide Werte mit dem ersten Element, damit das Ergebnis auf einem tatsächlich im Array enthaltenen Wert beruht. Das Beispiel verwendet dieselben Werte wie das ursprüngliche Array-Beispiel und durchläuft das Array einmal.

#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

Diese Funktion setzt ein nicht leeres Array und gültige Ergebniszeiger voraus. Der Aufrufer übergibt die Länge, weil ein Arrayparameter zu einem Zeiger angepasst wird; innerhalb von find_min_max misst sizeof(values) daher die Größe des Zeigers und nicht die des ursprünglichen Arrays. Hier berechnet sizeof die Elementanzahl in main, wo values noch ein Array ist: Teilen Sie die Gesamtgröße durch die Größe eines einzelnen Elements.

Verwenden Sie bei Gleitkommadaten einen einheitlichen Typ für das Array, die Variablen für Minimum und Maximum sowie die Funktionsparameter. Stimmen Sie die printf-Formatangabe auf den Typ des nach den Standardargumentumwandlungen übergebenen Werts ab; für einen double verwenden Sie %f. Soll die Funktion mehrere numerische Typen unterstützen, schreiben Sie passend typisierte Funktionen oder entwerfen Sie eine sorgfältig durchdachte Abstraktion, statt lediglich int durch float zu ersetzen.