Menu
Coddy logo textTech

Funktionszeiger in Structs

Teil des Abschnitts Object Oriented Programming der C-Journey von Coddy — Lektion 38 von 61.

Bisher haben wir Funktionszeiger als eigenständige Variablen verwendet oder sie als Argumente übergeben. Der nächste Schritt in Richtung Polymorphismus besteht darin, einen Funktionszeiger direkt in ein Struct einzubetten – was dem Struct sein eigenes Verhalten verleiht.

Wenn ein Struct einen Funktionszeiger enthält, kann jede Instanz eine andere Funktion enthalten. Das bedeutet, dass sich zwei Objekte desselben Typs unterschiedlich verhalten können, wenn Sie deren Funktionszeiger aufrufen:

typedef void (*PrintFunc)(const char*);

typedef struct {
    const char* name;
    PrintFunc print;  // Funktionszeiger als Member
} Printer;

Die Printer-Struct hat nun zwei Member: Daten (name) und Verhalten (print). Um sie zu verwenden, weisen Sie dem Pointer während der Initialisierung eine Funktion zu:

void loud_print(const char* msg) {
    printf("!!! %s !!!\n", msg);
}

int main() {
    Printer p;
    p.name = "Alert";
    p.print = loud_print;
    
    p.print("Hello");  // Ausgabe: !!! Hello !!!
    return 0;
}

Beachten Sie, wie wir die Funktion über das Struct aufrufen: p.print("Hello"). Dies sieht bemerkenswert ähnlich aus wie der Aufruf einer Methode für ein Objekt in anderen Sprachen. Das Struct trägt sowohl seine Daten als auch die Funktion, die darauf operiert.

Dieses Muster ist die Grundlage für Polymorphismus in C – verschiedene Instanzen können unterschiedliche Funktionen zugewiesen haben, was zu unterschiedlichen Verhaltensweisen desselben struct-Typs führt.

challenge icon

Aufgabe

Einfach

Lassen Sie uns ein Notifier-System bauen, das demonstriert, wie Structs ihr eigenes Verhalten durch Funktionszeiger mitführen können.

Sie werden zwei Dateien erstellen, um Ihren Code zu organisieren:

  • notifier.h: Definieren Sie einen Funktionszeigertyp namens NotifyFunc, der einen const char*-Parameter entgegennimmt und nichts zurückgibt. Definieren Sie dann ein Notifier-Struct, das einen name (ein const char*) und einen notify-Funktionszeiger vom Typ NotifyFunc enthält.
  • main.c: Binden Sie Ihren Header ein und implementieren Sie zwei Benachrichtigungsfunktionen:
    • alert_notify — gibt die Nachricht im Format [ALERT] message aus
    • info_notify — gibt die Nachricht im Format [INFO] message aus
    Erstellen Sie dann eine Notifier-Instanz, verknüpfen Sie die entsprechende Funktion basierend auf der Eingabe und rufen Sie die Benachrichtigung über den Funktionszeiger des Structs auf.

Ihr Programm erhält zwei Eingaben: einen Benachrichtigungstyp (1 für Alert, 2 für Info) und eine anzuzeigende Nachricht.

Weisen Sie basierend auf dem Typ die entsprechende Funktion dem notify-Member Ihres Notifiers zu und rufen Sie sie dann über das Struct auf, um die Nachricht anzuzeigen.

Beispielhafte Ausgabe, wenn der Typ 1 und die Nachricht "System starting" ist:

[ALERT] System starting

Beispielhafte Ausgabe, wenn der Typ 2 und die Nachricht "All systems normal" ist:

[INFO] All systems normal

Denken Sie daran, Include-Guards in Ihrer Header-Datei zu verwenden und die Funktion über das Struct-Member aufzurufen: n.notify(message)

Spickzettel

Funktionszeiger können direkt in Structs eingebettet werden, wodurch jede Instanz ihr eigenes Verhalten erhält. Dies ist eine Grundlage für Polymorphismus in C.

Definieren eines Structs mit einem Funktionszeiger

Definieren Sie zuerst einen Funktionszeigertyp und binden Sie ihn dann als Struct-Member ein:

typedef void (*PrintFunc)(const char*);

typedef struct {
    const char* name;
    PrintFunc print;  // Function pointer as a member
} Printer;

Verwendung des Structs

Weisen Sie dem Zeiger während der Initialisierung eine Funktion zu und rufen Sie diese dann über den Struct auf:

void loud_print(const char* msg) {
    printf("!!! %s !!!\n", msg);
}

int main() {
    Printer p;
    p.name = "Alert";
    p.print = loud_print;
    
    p.print("Hello");  // Output: !!! Hello !!!
    return 0;
}

Die Syntax p.print("Hello") ruft die Funktion über den Struct auf, ähnlich wie der Aufruf einer Methode für ein Objekt in anderen Sprachen.

Polymorphes Verhalten

Verschiedene Instanzen desselben Struct-Typs können unterschiedliche zugewiesene Funktionen haben, was zu unterschiedlichen Verhaltensweisen desselben Struct-Typs führt.

Probier es selbst

#include <stdio.h>
#include "notifier.h"

// TODO: Implementiere die alert_notify Funktion
// Sollte ausgeben: [ALERT] message


// TODO: Implementiere die info_notify Funktion
// Sollte ausgeben: [INFO] message


int main() {
    int type;
    char message[256];
    
    // Eingabe lesen
    scanf("%d", &type);
    getchar(); // Zeilenumbruch konsumieren
    fgets(message, sizeof(message), stdin);
    
    // Entferne abschließenden Zeilenumbruch von message, falls vorhanden
    int len = 0;
    while (message[len] != '\0') len++;
    if (len > 0 && message[len-1] == '\n') message[len-1] = '\0';
    
    // TODO: Erstelle eine Notifier Instanz
    
    
    // TODO: Basierend auf type (1 für alert, 2 für info),
    // weise die entsprechende Funktion dem notify Member des notifiers zu
    
    
    // TODO: Rufe die Benachrichtigung über den Funktionszeiger des structs auf
    // Verwende: n.notify(message)
    
    
    return 0;
}
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Object Oriented Programming