EMZETT.
Login

Kurz: Eine Funktion fasst Anweisungen zu einem benannten Baustein zusammen.

Teil des Kurses C

Kapitel 7 von 15 im Kurs C (Abschnitt „Funktionen und Speicher“). Mit Fortschritt, Quiz und Zertifikat auf der Lernseite.

Eine Funktion fasst Anweisungen zu einem benannten Baustein zusammen.

#include <stdio.h>
 
int addiere(int a, int b) {
    return a + b;
}
 
void gruss(const char *name) {
    printf("Hallo %s!\n", name);
}
 
double mittelwert(double a, double b) { return (a + b) / 2; }
 
int main(void) {
    printf("%d\n", addiere(3, 4));
    gruss("Mia");
    printf("%.1f\n", mittelwert(3, 4));
    return 0;
}

Ausgabe:

7
Hallo Mia!
3.5

Aufbau: Rückgabetyp name(Parameter) { ... return wert; }. void heißt “kein Rückgabewert”. main(void) bedeutet “keine Parameter” (() allein hieße in C: “unbekannt”).

Argumente werden kopiert (call by value)

C übergibt alles als Kopie. Eine Funktion kann Variablen des Aufrufers nur ändern, wenn du ihr die Adresse (einen Zeiger) gibst:

#include <stdio.h>
 
void falsch(int x)  { x = 99; }          // ändert nur die Kopie
void richtig(int *x) { *x = 99; }        // ändert das Original
 
void tausche(int *a, int *b) { int t = *a; *a = *b; *b = t; }
 
int main(void) {
    int n = 1;
    falsch(n);
    printf("%d\n", n);
    richtig(&n);
    printf("%d\n", n);
    int a = 1, b = 2;
    tausche(&a, &b);
    printf("%d %d\n", a, b);
    return 0;
}

Ausgabe:

1
99
2 1

Zeiger lernst du im übernächsten Kapitel genauer kennen.

Mehrere Ergebnisse zurückgeben

Mit Zeigern als “Ausgabeparameter” oder mit einer Struktur:

#include <stdio.h>
 
void minMax(const int *a, int n, int *min, int *max) {
    *min = *max = a[0];
    for (int i = 1; i < n; i++) {
        if (a[i] < *min) *min = a[i];
        if (a[i] > *max) *max = a[i];
    }
}
 
typedef struct { int min, max; } Bereich;
Bereich bereich(const int *a, int n) {
    Bereich b = { a[0], a[0] };
    for (int i = 1; i < n; i++) { if (a[i] < b.min) b.min = a[i]; if (a[i] > b.max) b.max = a[i]; }
    return b;
}
 
int main(void) {
    int z[] = {5, 3, 9, 1, 7};
    int mi, ma;
    minMax(z, 5, &mi, &ma);
    printf("%d %d\n", mi, ma);
    Bereich b = bereich(z, 5);
    printf("%d %d\n", b.min, b.max);
    return 0;
}

Ausgabe:

1 9
1 9

Rekursion

#include <stdio.h>
 
long fakultaet(int n) { return n <= 1 ? 1 : n * fakultaet(n - 1); }
int ggt(int a, int b) { return b == 0 ? a : ggt(b, a % b); }
void binaer(unsigned n) { if (n > 1) binaer(n / 2); putchar('0' + n % 2); }
 
int main(void) {
    printf("%ld %ld\n", fakultaet(10), fakultaet(20));
    printf("%d\n", ggt(48, 18));
    binaer(42); putchar('\n');
    return 0;
}

Ausgabe:

3628800 2432902008176640000
6
101010

Jede Rekursion braucht eine Abbruchbedingung. Zu tiefe Rekursion füllt den Stack (Absturz mit “Stack overflow”).

static und inline

  • static bei einer Funktion: nur in dieser Datei sichtbar (interne Verknüpfung)
  • static bei einer lokalen Variable: behält den Wert zwischen Aufrufen
  • inline ist ein Hinweis an den Compiler, den Funktionsrumpf einzusetzen

Funktionszeiger

Funktionen haben eine Adresse, und man kann sie in Variablen speichern und übergeben. So funktionieren Rückrufe (Callbacks), zum Beispiel bei qsort:

#include <stdio.h>
#include <stdlib.h>
 
static int vergleiche(const void *a, const void *b) {
    int x = *(const int *) a, y = *(const int *) b;
    return (x > y) - (x < y);
}
 
int plus(int a, int b) { return a + b; }
int mal(int a, int b) { return a * b; }
 
int wende(int (*f)(int, int), int a, int b) { return f(a, b); }
 
int main(void) {
    int z[] = {5, 3, 9, 1, 7};
    qsort(z, 5, sizeof z[0], vergleiche);
    for (int i = 0; i < 5; i++) printf("%d ", z[i]);
    printf("\n");
    printf("%d %d\n", wende(plus, 3, 4), wende(mal, 3, 4));
    int (*op)(int, int) = mal;
    printf("%d\n", op(6, 7));
    return 0;
}

Ausgabe:

1 3 5 7 9
7 12
42

Variable Argumentlisten

printf kann beliebig viele Argumente. Eigene Funktionen schreibst du mit <stdarg.h>:

#include <stdio.h>
#include <stdarg.h>
 
int summe(int anzahl, ...) {
    va_list args;
    va_start(args, anzahl);
    int s = 0;
    for (int i = 0; i < anzahl; i++) s += va_arg(args, int);
    va_end(args);
    return s;
}
 
int main(void) {
    printf("%d %d\n", summe(3, 1, 2, 3), summe(5, 10, 20, 30, 40, 50));
    return 0;
}

Ausgabe:

6 150

Merke

  • Rückgabetyp name(Parameter); void für “nichts”
  • Argumente werden kopiert; für Änderungen übergibst du Zeiger (&x, *p)
  • Mehrere Ergebnisse: Zeiger oder struct
  • Rekursion braucht eine Abbruchbedingung
  • Funktionszeiger ermöglichen Callbacks (qsort)
  • static bei Funktionen macht sie dateilokal

Übungsaufgabe

Schreibe potenz(basis, exp) einmal mit Schleife und einmal rekursiv sowie eine Funktion, die ein Array der Größe nach sortiert (mit qsort).

Quiz zur Selbstkontrolle

Weiter im Kurs

Zurück: Bedingungen und Schleifen

Weiter: Arrays und Strings

Alle Kapitel: C im Überblick