Zeigerhorror
-
Ich habe diese Definitionen:
typedef float TUPLE[2]; int readTuple(char* source, TUPLE** dest1, unsigned* currSize, unsigned* maxSize){ if(sscanf(source,"%f%f",&((*dest1)[(*currSize)][0]),&((*dest1)[(*currSize)][1])) != 2) return 0; else (*currSize) += 1; return 1; }
Die Funktion soll aus dem Paramter source 2 float Werte herauslesen, und das Ergebnis soll in dest1 hinterlegt werden können. Falls ein Fehler auftritt, soll der Aufrufer das anhand des Rückgabewerts überprüfen können
Ein Aufrufer soll also die Funktion z.B. so aufrufen können:
void aufrufer(){ int currSize = 0, maxSize = 10; TUPLE* Zahlentupel = (TUPLE*) malloc(maxSize*sizeof(TUPLE)); char lesebuffer[30] = {'\0'}; fgets(lesebuffer,30,stdin); // Also genau hier: readTuple(lesebuffer,&Zahlenbuffer, &currSize, &maxSize); }
Nach so einem Aufruf soll currSize außerdem entsprechend inkrementiert worden sein, und mithilfe des Parameters maxSize soll die readTuple Funktion im Bedarfsfall das TUPLE Array selbständig vergrößern können, wenn es nötig ist.
Mir ist hauptsächlich dieser Ausdruck rätselhaft:
&((*dest1)[(*currSize)][0])
Erreiche ich damit von der readTuple() Funktion aus den erwünschten Speicherort, der ja eigentlich zum Aufrufer() gehört, nämlich Zahlentupel[currSize][0], oder wo werden die Daten hingeschrieben?
Könnte man das irgendwie geschickter hinschreiben, damit es leichter nachvollziehbar ist, wohin die Daten von sscanf gespeichert werden ?
-
Also so wie es da steht, sollte das funktionieren:
Da du die Adresse des TUPLE-Arrays übergibst (&Zahlenbuffer), macht dir&((*dest1)[(*currSize)][0])
folgendes draus: dest1 dereferenziert dir den Pointer, sprich du Arbeitest mit Zahlenbuffer. Zahlenbuffer selbst ist ein Array, welches du mit Zahlenbuffer[(*currSize)] auf das aktuelle Element zeigen lässt. Die [0] bzw. [1] gibt dir nur noch den 1. bzw. 2. Wert in dem Tupel. currSize wird auch nochmal dereferenziert, da dort auch ein Pointer übergeben wird.
Ich finde das auch schwer zu lesen. Mein Vorschlag wäre, die currSize Variable in aufrufer() hoch zu zählen:typedef float TUPLE[2]; // wofuer brauchst du hier maxSize? int readTuple(char* source, TUPLE* dest1, unsigned currSize /*, unsigned* maxSize*/) { if( sscanf(source,"%f%f",&(dest1[currSize][0]),&(dest1[currSize][1])) != 2 ) return 0; return 1; } void aufrufer() { int currSize = 0, maxSize = 10; TUPLE* Zahlentupel = (TUPLE*) malloc(maxSize*sizeof(TUPLE)); char lesebuffer[30] = {'\0'}; fgets(lesebuffer,30,stdin); // return-Wert auswerten und entsprechend currSize hochzaehlen if( readTuple(lesebuffer, Zahlenbuffer, currSize /*, &maxSize*/) ) currSize++; }
Würde das zwar noch testen, ob es reicht, dass man nur den Pointer Zahlenbuffer übergibt und nicht den Pointer auf den Pointer Zahlenbuffer, aber sollte so schon funktionieren.
-
Besten Dank, hab's kompiliert und es scheint so zu funktionieren, wie ich mir das erhofft habe. Die Inkrementierung werde ich in den Aufrufer verlegen
Weil readTuple() im Bedarfsfall realloc() aufruft, wenn der Platz im Tupel** dest1 nicht ausreicht, war ich mir nicht sicher, ob es genügt, einfach nur Tupel* zu übergeben, weil vermutlich arbeitet readTuple nur mit einer byValue Kopie des Zeigers in dest1, und wenn ich dann z.B. innerhalb von readTuple nurdest1 = (TUPLE*) realloc(dest1,NEUE_GROESSE);
schreibe, bekommt womöglich der Originalzeiger im Aufrufer() nichts davon mit, dass der Speicherblock vergroessert und womoeglich gar verschoben wurde.
Würde zu gerne wissen, ob realloc() dabei intelligent genug ist, um auch den Zeiger im Aufrufer() entsprechend zu verschieben, wenn es nötig ist. (?)