2016-04-08 3 views
-3

Einen Link zu dem Projekt in GithubC „für“ -Schleife ändert Zeigerwert in einer Funktion

So habe ich ein Problem mit Fall 5 innerhalb der Hauptfunktion. Wo load_array() aufgerufen wird. Die eigentliche Funktion befindet sich in functions.c on line 120

Das Problem ist, dass die for-Schleife von 5 den Wert von int * Größe ändert sich auf 23

+0

Sie haben gezeigt, wie Sie rufen 'load_array' was eine gute Idee ist, aber es ist nicht genug, bitte zeigen, wie' file_name', ' Elemente "und" arr "werden deklariert. Was ist "init"? –

+1

Es gibt nicht genügend Informationen. Zusätzlich zu der Umgebung, in der 'load_array' aufgerufen wird, was macht' init'? Meinst du nicht "int ** p", so dass "init" zu "* p" zuordnen kann? –

+1

Worauf deutet 'p' hin? Es sieht wie ein klassischer Pufferüberlauf aus, wobei "p" wahrscheinlich auf eine automatische Variable verweist, die auf dem Stapel zugewiesen ist, die kein Array von mindestens "sz" -Ints ist. –

Antwort

3

Der Compiler hätte Sie anschreien sollen, weil das letzte Argument, das Sie an load_array übergeben, nicht mit dem formalen Argument der Funktion übereinstimmt und es wiederum nicht mit dem übereinstimmt, was init erwartet.

Und wenn, wenn p im load_array Funktion ist in der Tat ein Zeiger auf einen Zeiger (d.h. das Argument int **p), dann der scanf Anruf falsch als Ausdruck (p + i) wird auch ein Zeiger auf einen Zeiger. Und das ist höchstwahrscheinlich die Ursache Ihres Problems, da es zu undefiniertem Verhalten führt und die Eingabe an anderer Stelle als erwartet schreiben wird.

Um dies zu beheben, müssen Sie zunächst den Argumenttyp korrigieren und dann den Dereferenzoperator verwenden, wenn Sie verwenden, wie in *p + i.

Kurz gesagt, zu stimmen der Code wie

aussehen sollte
//    Note extra asterisk here 
//          | 
//          v 
void load_array(char* fn, int* size, int** p) 
{ 
    ... 
    // Note extra asterisk here 
    //    | 
    //    v 
    fscanf(fp, "%d", *p + i); 
    // Or fscanf(fp, "%d", &(*p)[i]); 
    ... 
} 
+0

Danke, das hat für mich funktioniert. – Kyojin

1

Jetzt haben wir genug Code zu gehen. Erstens soll load_array ein Array zuweisen und füllen, wobei seine Position und Größe über zwei Zeiger zurückgegeben wird, von denen einer als inout (Größe) und der andere nur als Ausgabe (p) dient. init soll die Zuweisung tun, und es gibt eine Aufrufseite, die die Variablen int elements und (vermutlich) int *arr=NULL enthält.

Das Problem ist, diese werden nicht als der gleiche Typ auf dem Weg übergeben. Der Anruf an load_array nimmt die Adresse arr, also eine int**, aber die Erklärung sagt, es ist nur ein int*. Es wird an init übergeben, das eine int** erwartet, und es funktioniert wahrscheinlich dort, wie es tatsächlich war (aber es ist immer noch eine ungültige Möglichkeit, Zeigertypen zu konvertieren), aber wenn load_array beginnt, Dinge zu füllen, schreibt es an p+i.

p an diesem Punkt zeigt auf arr, das ist kein int, also selbst wenn i niedrig ist, ist dies der falsche Ort, um die Daten zu setzen. Dies verursacht erstens den Verlust des Puffers arr, auf den verwiesen wird, zweitens ungültige Daten in arr, so dass späterer Zugriff zu undefiniertem Verhalten führt, und drittens (einmal i wird größer als sizeof(int*)/sizeof(int)) das Überschreiben von nicht verwandtem Speicher, wie dem Inhalt von elements wahrscheinlich eine Nachbarvariable.

Eine wahrscheinliche Speicherlayout könnte sein, dass elements auf dem Stapel liegt, sagen wir mal FP + 12..15, dann zu halten arr vier ungenutzten Bytes an FP ausgerichtet sind + 8..11 und arr sitzt in FP + 0..7. Dies würde erklären, warum der Schritt i=3 insbesondere bewirkt, dass sich elements (alias *size) ändert.

Was Sie tun sollten, ist die Art der p fixieren und verwenden *p in load_array, ähnlich wie es in init verwendet wird.

Verwandte Themen