Benötige Hilfe beim verstehen von Codezeilen mit Doppelpointern
-
Hallo,
ich bin gerade dabei mich in C einzuarbeiten und ich bräuchte nun, da ich noch Recht am Anfang stehe, Hilfe beim verstehen einiger Zeilen Code.
Ich zitier einfach mal den Text und stelle danach speziell die Fragen (nur um den Hintergrund zu geben, es geht um eine Funktion die Daten aus dem Speicher liest und den Pointer, der die Stelle im Speicher zeigt, abspeichert):
"Die Funktion GetBlockData() muss folgendermassen implementiert werden:
0 typedef uint8* BlockDataType; 1 FUNC(void, PUBLIC_CODE) 2 GetBlockData( BlockIdType blockId, P2VAR(BlockDataType,AUTOMATIC,VAR_DATA) blockData ) 3 { 4 uint8** ppReturn = (uint8**)blockData; 5 *ppReturn = &NData.data[BlockDescriptorTable[blockId].dataOffset ]; 6 }
"
Mein Verständnis:
Zeile 1: Funktionskopf, Funktion ist vom Typ void und öffentlich zugreifbarZeile 2: Funktionsname "GetBlockData", hat zwei Eingabeparameter: blockId und blockData. Dies macht für mich gerade keinen Sinn, denn ich will ja gerade die Bockdaten wissen. D.h. ich würde erwaten nur die ID als Eingabeparameter zu deklarieren und der Rückgabe Wert ist " blockData" wobei der Pointer (P2VAR) in eine Variable vom Typ "BlockDataType" umgewandelt wird. Somit macht die Implemenierung so keinen Sinn für mich oder ich versteh sie einfach nicht.
Zeile 4: jetzt beginnen meine richtigen Probleme ich versteh die ** (diese Doppelpointer) überhaupt nicht mehr. Wird hier nun die Adresse von blockData auf ppReturn übergeben?
Zeile 5: Hier wird nun nochmals etwas auf die Variable *ppReturn geschrieben, aber ich kapier den einzelnen * davor nicht? Die Übergabe was nun geschrieben wird und was nun mit dem alten Wert von ppReturn passiert ist mir schleierhaft.
Der Rest "&NData..." das is nun der dataOffset Wert der hier zugewiesen wird oder?Wäre echt gut, wenn mir jemand dabei helfen könnte. Vielen Dank schon mal!!!
Azador
-
Hi!
Azador schrieb:
"Die Funktion GetBlockData() muss folgendermassen implementiert werden:
Muss? Sagt wer?
Azador schrieb:
... FUNC(void, PUBLIC_CODE)... ... P2VAR(BlockDataType,AUTOMATIC,VAR_DATA) blockData ) ...
Wenn du mich fragst, ist das C-Stil übelster Sorte. Um genau erklären zu können, was der Code macht, müsstest du dir die Macros FUNC und P2VAR mal genauer angucken.
... wobei der Pointer (P2VAR) in eine Variable vom Typ "BlockDataType" umgewandelt wird ...
P2VAR ist ein Macro mit drei Parametern, das einen Datentypen generiert.
Vor dem Kompilieren, nach der Ausführung des Macros sieht die Parameterliste von GetBlockData so aus:
GetBlockData( BlockIdType blockId, T blockData ), wobei T der generierte Datentyp ist.Zeile 4: jetzt beginnen meine richtigen Probleme ich versteh die ** (diese Doppelpointer) überhaupt nicht mehr. Wird hier nun die Adresse von blockData auf ppReturn übergeben?
Was auch immer in blockData drin stehen mag, dieser Wert ist vom Typ T und wird in einen Wert vom Typ uint8** gecastet und der zugehörigen Variable ppReturn zugewiesen.
Zeile 5: Hier wird nun nochmals etwas auf die Variable *ppReturn geschrieben, aber ich kapier den einzelnen * davor nicht? Die Übergabe was nun geschrieben wird und was nun mit dem alten Wert von ppReturn passiert ist mir schleierhaft.
ppReturn ist ein Zeiger auf einen Zeiger. Mit *ppReturn wird das erste Element dereferenziert, diesem Wird "&NData..." zugeweisen.
Zeile 2: Funktionsname "GetBlockData", hat zwei Eingabeparameter: blockId und blockData. Dies macht für mich gerade keinen Sinn, denn ich will ja gerade die Bockdaten wissen. D.h. ich würde erwaten nur die ID als Eingabeparameter zu deklarieren und der Rückgabe Wert ist " blockData" wobei der Pointer (P2VAR) in eine Variable vom Typ "BlockDataType" umgewandelt wird. Somit macht die Implemenierung so keinen Sinn für mich oder ich versteh sie einfach nicht.
Die Funktion hat offensichtlich keinen Rückgabewert, sie gibt nichts zurück. Die Blockdaten, die du wissen willst, sollten jetzt über den zweiten Parameter abrufbar sein, den du an die Funktion GetBlockData übergeben hast.
Das wird vermutlich ein Zeiger auf einen Zeiger sein, hinter dem allokierter RAM steckt.
Diese Art von "Rückgabe" ist bei void Funktionen durchaus üblich, ein Beispiel:char* new_string_a() // Eine Funktion mit Rückgabewert. { char* a = malloc(20); if(a) strcpy(a, "hello world"); return a; } // Die gleiche Funktion in grün, ohne Rückgabewert, // entspricht im Prinzip deiner GetBlockData Funktion void new_string_b(char** b) { char* a = malloc(20); if(a) strcpy(a, "hello world from void"); *b=a; } int main() { char* s; s = new_string_a(); if(s) { puts(s); free(s); } new_string_b(&s); if(s) { puts(s); free(s); } getchar(); return 0; }
Gruß,
*0r
-
ooops, das zweite malloc braucht etwas mehr food!
strlen("hello world from void") > 20 !
-
Also echt Danke schon mal für die fixe Antwort, aber ganz hab ich es noch nicht kapiert.
Zeile 4: blockData wird auf den Datentyp uint8** gecastet. Ok, uint8 sagt mir was, aber ich kann mir grad nix unter den ** vorstellen.
uint8 data
-> data ist vom Datentyp uint8uint8 *data
-> die zeigervariable *data wird deklariert. Speicherbereich für die Adresse von *data wird reserviert.uint8 **data
->????Zeile 5: Deine Erklärung mit dem ersten Element hab ich nicht ganz verstanden? Wäre schön, wenn du es bitte vielleicht nochmals mit anderen Worten versuchen könntest.
Ansonsten noch ein Kommentar zu Zeile 5:
*ppReturn = &NData....ppReturn zeigt nun auf die Adresse von &NData..ist das Richtig?
Was bekomme ich nun für die Adresse von *ppReturn in dem Fall und für **ppReturn?
-
Azador schrieb:
Ok, uint8 sagt mir was, aber ich kann mir grad nix unter den ** vorstellen.
Hinter uint8 könnte ein unsigned char stecken. Musste mal das zugehörige typedef suchen.
Die beiden Sternchen ** bedeuten in Worten: Zeiger auf Zeiger.
http://www.win-tux.de/c_014_008.htm#RxxobKap014008040028C21F04A18CAzador schrieb:
Zeile 5: Deine Erklärung mit dem ersten Element hab ich nicht ganz verstanden? Wäre schön, wenn du es bitte vielleicht nochmals mit anderen Worten versuchen könntest.
&
Azador schrieb:
uint8 **data
->????Vielleicht hilft das:
typedef unsigned char uint8; uint8 d = 7; void change_me(uint8** data) { *data = &d; } int main() { uint8 a = 6; uint8* b = &a; // b 'zeigt' auf a, d.h. b hat die Adresse von a gespeichert. uint8** c = &b; // c 'zeigt' auf b, d.h. c hat die Adresse von b gespeichert. printf("%d\n", *b); // Sternchen (Inhaltsoperator) dereferenziert b. change_me(c); // äquivalent zu change_me(&b); printf("%d\n", *b); printf("%d\n", **c); // c** ist äquivalent zu *b. getchar(); return 0; }
Azador schrieb:
Ansonsten noch ein Kommentar zu Zeile 5:
*ppReturn = &NData....ppReturn zeigt nun auf die Adresse von &NData..ist das Richtig?
Was bekomme ich nun für die Adresse von *ppReturn in dem Fall und für **ppReturn?ppReturn zeigt auf NData...
Gruß,
B.B.