Wiederholung: Void-Pointer
Teil des Abschnitts Object Oriented Programming der C-Journey von Coddy — Lektion 49 von 61.
Ein void* ist die Art und Weise in C zu sagen: „ein Zeiger auf etwas, aber ich verrate dir nicht, was.“ Er kann die Adresse jedes Datentyps speichern – eines int, eines float, eines Structs oder von irgendetwas anderem. Dies macht ihn zur Grundlage für das Schreiben von generischem Code in C.
Der Haken dabei ist, dass man einen void* nicht direkt dereferenzieren kann. Der Compiler weiß nicht, wie viele Bytes er lesen oder wie er sie interpretieren soll. Um die Daten zu verwenden, müssen Sie sie in den korrekten Typ zurück umwandeln (casten):
void print_int(void* data) {
int* p = (int*)data;
printf("%d\n", *p);
}
int main() {
int x = 42;
print_int(&x);
return 0;
}Diese Flexibilität bringt Verantwortung mit sich. Wenn Sie in den falschen Typ umwandeln, wird der Compiler Sie nicht daran hindern – aber Ihr Programm wird fehlerhafte Daten produzieren oder abstürzen. Aus diesem Grund kombinieren generische Funktionen oft einen void* mit einem Typindikator (wie einem Enum oder Flag), damit die Funktion weiß, wie sie die Daten korrekt interpretieren soll.
In den kommenden Lektionen werden Sie void* verwenden, um Container zu erstellen, die jede Art von Daten speichern können, was wirklich wiederverwendbare Datenstrukturen ermöglicht.
Aufgabe
EinfachSchreiben Sie eine Funktion namens print_value, die zwei Parameter akzeptiert: einen void*-Zeiger auf Daten und ein int-Typ-Flag. Die Funktion soll die Daten basierend auf dem Typ-Flag interpretieren und ausgeben:
- Wenn das Typ-Flag
0ist, wandeln Sie den Zeiger in einenint*um und geben Sie den Integer-Wert aus. - Wenn das Typ-Flag
1ist, wandeln Sie den Zeiger in einenfloat*um und geben Sie den Float-Wert mit 2 Dezimalstellen aus.
Ihr Programm erhält zwei Eingaben:
- Ein Typ-Flag (
0für Integer,1für Float) - Einen numerischen Wert
Speichern Sie den Wert basierend auf dem Typ-Flag in dem entsprechenden Variablentyp und rufen Sie dann print_value mit einem Zeiger auf diese Variable und dem Typ-Flag auf.
Beispielhafte Ausgabe, wenn die Eingaben 0 und 42 sind:
42Beispielhafte Ausgabe, wenn die Eingaben 1 und 3.14 sind:
3.14Beispielhafte Ausgabe, wenn die Eingaben 0 und -17 sind:
-17Beispielhafte Ausgabe, wenn die Eingaben 1 und 99.5 sind:
99.50Spickzettel
Ein void* ist ein generischer Zeiger, der die Adresse eines beliebigen Datentyps speichern kann. Er bietet Flexibilität beim Schreiben von generischem Code in C.
Ein void* kann nicht direkt dereferenziert werden – er muss zuerst in den richtigen Typ umgewandelt (gecastet) werden:
void print_int(void* data) {
int* p = (int*)data;
printf("%d\n", *p);
}
int main() {
int x = 42;
print_int(&x);
return 0;
}Generische Funktionen kombinieren oft einen void* mit einem Typindikator (wie einem Enum oder Flag), um zu wissen, wie die Daten korrekt zu interpretieren sind. Das Umwandeln in den falschen Typ kann zu undefiniertem Verhalten oder Abstürzen führen.
Probier es selbst
#include <stdio.h>
// TODO: Schreiben Sie hier Ihre print_value-Funktion
int main() {
int type_flag;
scanf("%d", &type_flag);
if (type_flag == 0) {
int int_value;
scanf("%d", &int_value);
// TODO: Rufen Sie print_value mit einem Zeiger auf int_value und dem type_flag auf
} else if (type_flag == 1) {
float float_value;
scanf("%f", &float_value);
// TODO: Rufen Sie print_value mit einem Zeiger auf float_value und dem type_flag auf
}
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 Box7Funktionszeiger
Funktionszeiger deklarierenFunktionszeiger aufrufenTypedef für FunktionszeigerFunktionen als Argumente übergebenZusammenfassung: Calculator Dispatch10Generische Container
Wiederholung: Void-PointerGenerischer WrapperGenerisches SwapGenerisches VergleichenWiederholung: Generisches Array2Objekte 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