Der 'Self'-Pointer
Teil des Abschnitts Object Oriented Programming der C-Journey von Coddy — Lektion 7 von 61.
In objektorientierten Sprachen wie Python oder Java übergibt die Sprache das Objekt selbst automatisch an die Methode, wenn man object.method() aufruft. In C müssen wir dies manuell tun, indem wir einen Zeiger auf das Struct als erstes Argument übergeben.
Dieser Zeiger wird üblicherweise self (aus Python übernommen) oder this (aus C++) genannt. Er gibt der Funktion Zugriff auf die Daten des Structs, sodass sie diese lesen oder ändern kann:
typedef struct {
int health;
} Player;
void player_take_damage(Player *self, int amount) {
self->health -= amount;
}
Der self-Pointer lässt die Funktion wie eine Methode agieren – er weiß, welchen Spieler er modifizieren soll. Ohne ihn hätte die Funktion keine Möglichkeit, auf die spezifische Struct-Instanz zuzugreifen. Beim Aufrufen dieser Funktion übergibst du die Adresse deines Structs:
Player hero = {100};
player_take_damage(&hero, 25);
// hero.health ist jetzt 75
Die Verwendung eines Pointers (anstatt das Struct direkt zu übergeben) ist für Modifikationen unerlässlich. Wenn Sie das Struct per Wert (by value) übergeben würden, würde die Funktion eine Kopie erhalten, und alle Änderungen gingen verloren, wenn die Funktion zurückkehrt. Der Pointer stellt sicher, dass Änderungen im ursprünglichen Struct erhalten bleiben.
Aufgabe
EinfachLassen Sie uns ein Timer-Modul bauen, das die verstrichenen Sekunden verfolgt. Sie werden üben, das "self"-Pointer-Muster zu verwenden, um den internen Zustand eines Structs durch Funktionen zu ändern, die wie Methoden agieren.
Sie werden drei Dateien erstellen:
timer.h: Deklarieren Sie einTimer-Struct mit einem einzelnenint seconds-Member. Deklarieren Sie außerdem zwei Funktionen:timer_tick(nimmt einen Zeiger auf Timer entgegen und addiert eine bestimmte Anzahl von Sekunden) undtimer_reset(nimmt einen Zeiger auf Timer entgegen und setzt die Sekunden zurück auf Null). Verwenden Sie Include-Guards mit dem SymbolTIMER_H.timer.c: Implementieren Sie beide Funktionen. Die Funktiontimer_ticksollte einenTimer *selfund einint amountakzeptieren und dann den Betrag zu den Sekunden des Timers addieren. Die Funktiontimer_resetsollte einenTimer *selfakzeptieren und dessen Sekunden auf Null setzen.main.c: Erstellen Sie einen Timer, führen Sie Operationen damit aus und zeigen Sie die Ergebnisse an.
Sie erhalten zwei Ganzzahl-Eingaben: die initial seconds für Ihren Timer und den amount to add via Tick.
In Ihrer Hauptdatei:
- Initialisieren Sie einen
Timermit dem Wert der initialen Sekunden - Rufen Sie
timer_tickauf, um den angegebenen Betrag hinzuzufügen - Geben Sie die aktuellen Sekunden aus
- Rufen Sie
timer_resetauf, um den Timer zurückzusetzen - Geben Sie die Sekunden erneut aus (sollte 0 sein)
Geben Sie die Ergebnisse in diesem Format aus:
After tick: {seconds}
After reset: {seconds}Zum Beispiel, bei einem Initialwert von 30 und dem Hinzufügen von 15 Sekunden, wäre die Ausgabe:
After tick: 45
After reset: 0Spickzettel
In C benötigen Funktionen, die auf Structs operieren, expliziten Zugriff auf die Struct-Instanz über einen Zeiger-Parameter, der konventionell self oder this genannt wird:
typedef struct {
int health;
} Player;
void player_take_damage(Player *self, int amount) {
self->health -= amount;
}
Der self-Zeiger ermöglicht es der Funktion, auf die Daten des Structs zuzugreifen und diese zu ändern. Wenn Sie solche Funktionen aufrufen, übergeben Sie die Adresse Ihres Structs:
Player hero = {100};
player_take_damage(&hero, 25);
// hero.health ist jetzt 75
Die Verwendung eines Zeigers ist für Änderungen unerlässlich – die Übergabe als Wert (pass by value) würde eine Kopie erstellen, und Änderungen gingen verloren, wenn die Funktion zurückkehrt. Der Zeiger stellt sicher, dass Änderungen im ursprünglichen Struct erhalten bleiben.
Probier es selbst
#include <stdio.h>
#include "timer.h"
int main() {
int initial_seconds, amount_to_add;
scanf("%d", &initial_seconds);
scanf("%d", &amount_to_add);
// TODO: Erstellen Sie einen Timer und initialisieren Sie ihn mit initial_seconds
// TODO: Rufen Sie timer_tick auf, um amount_to_add Sekunden hinzuzufügen
// TODO: Geben Sie die aktuellen Sekunden im Format "After tick: {seconds}" aus
// TODO: Rufen Sie timer_reset auf, um den Timer zurückzusetzen
// TODO: Geben Sie die Sekunden erneut im Format "After reset: {seconds}" aus
return 0;
}
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
1Grundlagen der modularen Programmierung
Header-DateienInclude GuardsQuelldateienStatische FunktionenWiederholung: Modularer Taschenrechner4Kapselung
Konzept der Opaque PointersOpaque Structs definierenGetter und SetterValidierung in SetternRückblick: Die geheime Box2Objekte und Methoden
Structs als ObjekteDer 'Self'-PointerConst-CorrectnessPointer vs. WertHilfsmethodenZusammenfassung: Point Manager5Projekt: Einfaches Bankkonto
Projekt-SetupImplementierung des Kontos3Objekt-Lebenszyklus
Konstruktor-MusterDestruktor-MusterStack-InitialisierungTiefe KopieRückblick: String-Wrapper6Vererbung durch Komposition
Struct-EinbettungDie First-Member-RegelZugriff auf Parent-MemberUpcastingRückblick: Formenhierarchie9Projekt: Formen-Zeichner
ProjektübersichtKreis-Implementierung