Fragen zum Verständnis von void
-
Z schrieb:
Es schränkt den Typ weiter ein als nur "Zeiger auf etwas".
Das hört sich erstmal ganz logisch an. Aber wenn man bedenkt, dass void* ein Zeiger auf etwas Beliebiges ist, dann dann kann dieses Beliebige auch ein Zeiger auf Zeiger sein.
Aber eben nicht umgekehrt. Das ist es doch gerade, worum es geht!
-
Das hört sich erstmal ganz logisch an. Aber wenn man bedenkt, dass void* ein Zeiger auf etwas Beliebiges ist, dann dann kann dieses Beliebige auch ein Zeiger auf Zeiger sein.
Nach der Argumentation müsste man Zeiger grundsätzlich als void* deklarieren.
-
Genau.
T*
ist weiter eingeschränkt* alsvoid*
, und daher vorzuziehen wenn es sich wirklich um einenT*
handelt.
replace("T", "void*")
void**
ist weiter eingeschränkt* alsvoid*
, und daher vorzuziehen wenn es sich wirklich um einenvoid**
handelt.*: weiter eingeschränkt = weniger leicht falsch zu verwenden, beinhaltet mehr Informationen etc.
@Z
Wieso zitierst du den Satz "Es schränkt den Typ weiter ein als nur "Zeiger auf etwas".", ignorierst ihn in deine Antwort dann aber total?Z schrieb:
Aber wenn man bedenkt, dass void* ein Zeiger auf etwas Beliebiges ist, dann dann kann dieses Beliebige auch ein Zeiger auf Zeiger sein.
Ich frage mich, ob es irgendeinen sinnvollen Anwendungsfall für void** gibt.
Du musst bloss lesen was ich schreibe.
void*
wird z.B. oft als Zeiger auf "einfach Speicher" verwendet - wie beimemcpy
etc.
Und wenn du jetzt einen Zeiger auf so einen Zeiger auf "einfach Speicher" hast, dann ist das Typ davon natürlichvoid**
.Oder: klassische C Type-Erasure --> man arbeitet mit
void*
. Wenn du jetzt eine Funktion hast die so einenvoid*
befüllen muss, dann übergibst du natürlich einenvoid**
.void Fun(void** ppv) { SomeType* px = ...; *ppv = px; }
Was ist daran so schwer zu verstehen?
-
Z schrieb:
Ich frage mich, ob es irgendeinen sinnvollen Anwendungsfall für void** gibt.
Jup. Sobald man Graphen hat und für die Generizität statt KnotenFooBarEbbes* gerne void* mag, da hat man für KanteFooBarEbbes*==*KnotenFooBarEbbes eben void**. Und es fühlt sich gut an, gibt auf Anhieb fehlerfreien Code, speicherlochfrei, effizient und wartbar. Wenn die Datenstruktur danach verlangt.
-
Danke, Volkard.
Ich erinnere mich, sowas ähnliches tatsächlich mal gesehen zu haben.
-
@Husti, dass man void** irgendwie verwenden kann, war nicht meine Frage.
-
Hi,
Vielen Dank für eure hilfreichen Antworten und Erklärungen, sie haben mir beim Verstehen von void sehr geholfen.
Mit void** wollte/möchte ich eine Funktion schreiben, die sowohl zwei Werte im beliebigen Format als auch 2 Arrays im beliebigen Format austauscht. Die Idee wäre eine Erweiterung von der Funktion für Austausch von 2 Integer-Werte / Int-Arrays mit pointer of pointer.
Nun mein Code in header Datei:
void tauschTowZeiger(int **i, int **j){ printf("\n Die Werte VOR: %d, %d \n", **i, **j); int* tmpZeiger = *i; *i = *j; *j = tmpZeiger; printf("\n Die Werte NACH: %d, %d \n", **i, **j); } void exchangTowPointerUniversal(void **i, void **j){ printf("\n Die Werte VOR: %d, %d \n", **i, **j); void* tmpZeiger = *i; *i = *j; *j = tmpZeiger; printf("\n Die Werte NACH: %d, %d \n", **i, **j); }
Die 2. Funktion habe ich völlig nach der ersten nachgebaut und dachte dass ich die ausgetauschten Werte auch direkt in der Funktion ausgeben könnte...
Das ist ja mein 1.Problem zu wissen ob ich wirklich den Wert ausgeben kann?
Mein 2. Problem ist, ich rufe die 2. Funktion in meiner Main-Methode auf, werden aber die Werte nicht getauscht ... warum?
Aufruf in der Main:
//typenlose Variablen tauschen float af = 7.56; float bf = 9.81; float* afp = ⁡ float* bfp = &bf; printf("\n Typenlose Werte %d und %d tauschen für int. \n", inta, intb); exchangTowPointerUniversal((void**)&pp1, (void**)&pp2); printf("\n Die getauschte 1. Zahl %d und 2. Zahl %d \n", inta, intb); printf("\n Typenlose Werte %f und %f tauschen für float. \n", af, bf); exchangTowPointerUniversal((void**)&afp, (void**)&bfp); printf("\n Die getauschte 1. Zahl %f und 2. Zahl %f \n", af, bf);
Vielen Dank!!!
LG, Carvin
-
hanowde schrieb:
Die 2. Funktion habe ich völlig nach der ersten nachgebaut und dachte dass ich die ausgetauschten Werte auch direkt in der Funktion ausgeben könnte...
Das ist ja mein 1.Problem zu wissen ob ich wirklich den Wert ausgeben kann?
Wenn du in der Funktion weißt, welcher Typ das ist, kannst du entsprechen casten.
printf("\n Die Werte NACH: %d, %d \n", *((int*)*i), *((int*)*j));
Aber dann kannst du gleich die erste Version nehmen.
hanowde schrieb:
Mein 2. Problem ist, ich rufe die 2. Funktion in meiner Main-Methode auf, werden aber die Werte nicht getauscht ... warum?
Du hast nur die Zeiger getausch und nicht die Werte.
printf("\n Typenlose Werte %f und %f tauschen für float. \n", *afp, *bfp); exchangTowPointerUniversal((void**)&afp, (void**)&bfp); printf("\n Die getauschte 1. Zahl %f und 2. Zahl %f \n", *afp, *bfp);
-
Hi, DirkB
Danke für deine Antwort.
Mit der 1. Funktion für integer habe ich zwei int-Zahlen erfolgreich getauscht, weil die Adressen von Zeiger auf Zeiger getauscht wurden.
Die 2. Funktion für typenlose Variablen sollte auch das Gleiche machen, warum werden die Zahlen nicht getauscht?
Danke.
LG, Carvin
-
hanowde schrieb:
Mit der 1. Funktion für integer habe ich zwei int-Zahlen erfolgreich getauscht
Nein, hast du nicht. Du hast zwei Zeiger getauscht.
-
Z schrieb:
@Husti, dass man void** irgendwie verwenden kann, war nicht meine Frage.
Du ignorierst Dinge die ich dir schreibe um mich falsch bzw. nicht verstehen zu können. Und wenn ich dir ein Beispiel zeige nennst du es unsinnig.
Ich glaube nicht dass ich mich weiter mit dir unterhalten muss.
-
void ist kein Variant-Typ oder ähnliches
void ist kein Value/Storage-Typed.h. void nimmt keinen Platz im Speicher ein und kann auch absolut nichts speichern
daher gibt es void nur "freistehend" als Platzhalter für Funktionen die nichts zurueckliefern, oder
als void* - einem typenlosem Pointer auf Daten der noch nicht mal Zeigerarithmetik versteht, Zugriff auf die Daten dahinter funktioniert nur mit einem cast - weil void ja kein Typ ist
d.h. du kann void-Zeiger herumreichen, austauschen, vergleichen, casten - aber sonst einfach gar nichts
deine Verwendung von void* ist komisch/ungwöhnlich und Zeiger scheinen auch noch nicht wirklich deine stärke zu sein
-
@Gast3
An wen ist dein Beitrag gerichtet?
-
an hanowde
wenn ich seine Posts so durchlese kommt bei mir das "Gefühl" auf als wenn da jemand nicht 100% versteht wofür void da ist oder genutzt werden soll(kann)
-
Gast3 schrieb:
wenn ich seine Posts so durchlese kommt bei mir das "Gefühl" auf als wenn da jemand nicht 100% versteht wofür void da ist oder genutzt werden soll(kann)
Das Gefühl hatte ich schon beim Lesen des Thread-Titels ...
-
Gast3 schrieb:
void ist kein Variant-Typ oder ähnliches
void ist kein Value/Storage-Typed.h. void nimmt keinen Platz im Speicher ein und kann auch absolut nichts speichern
daher gibt es void nur "freistehend" als Platzhalter für Funktionen die nichts zurueckliefern, oder
als void* - einem typenlosem Pointer auf Daten der noch nicht mal Zeigerarithmetik versteht, Zugriff auf die Daten dahinter funktioniert nur mit einem cast - weil void ja kein Typ ist
d.h. du kann void-Zeiger herumreichen, austauschen, vergleichen, casten - aber sonst einfach gar nichts
deine Verwendung von void* ist komisch/ungwöhnlich und Zeiger scheinen auch noch nicht wirklich deine stärke zu sein
void* speichert einfach nur adressen. typ egal.
void** allerdings speichert zeiger auf void*, also ist wieder typisiert.
das ist alles. ohne hustenbären-hokuspokus.
-
user02 schrieb:
das ist alles. ohne hustenbären-hokuspokus.
Lol.
Du hast so keine Ahnung wie gut Hustbär ist.Lies einfach mit und lern.
-
s/Hustbär/hustbaer/
-
Furble Wurble schrieb:
Du hast so keine Ahnung wie gut Hustbär ist.
das arrogante bärli ist jedenfalls gut im schwätzen.
darum hab ichs auch erwähnt.