Verwirrt durch die einzelnen Zeiger und Doppel-pointer-Argumente in Funktionsaufrufen
Ich versuche, ein tieferes Verständnis über pointer-Argumente in Funktionen für C. ich geschrieben habe ein test-Programm, um zu versuchen, um den Unterschied zu sehen zwischen der Weitergabe einer einzigen Zeiger vs double Zeiger auf eine Funktion, und dann zu modifizieren.
Ich habe ein Programm, das zwei Funktionen hat. Die erste Funktion modifyMe1
mit einem einzigen Zeiger als argument und ändert eine Eigenschaft zum 7. Die zweite Funktion modifyMe2
nimmt einen double-pointer als argument und ändert eine Eigenschaft zum 7.
Ich erwartet, dass die erste Funktion modifyMe1
wäre: "pass-by-value", das ist, wenn ich ging in mein struct-pointer, C schaffen würde, eine Kopie der Daten zeigte es. Während bei den letzteren, ich bin dabei ein "pass-by-reference", das sollte ändern Sie die Struktur an Ort und Stelle.
Jedoch, wenn ich testen Sie dieses Programm aus, beide Funktionen scheinen zu ändern, die Struktur im Ort. Ich weiß, es ist ein Missverständnis für mich auf die Art der Zeiger-Argumente für sicher. Kann mir jemand helfen, deaktivieren Sie dies für mich?
Dank!
Hier ist was ich habe:
#include <stdio.h>
#include <stdlib.h>
struct myStructure {
int a;
int b;
};
void modifyMe1(struct myStructure *param1) {
param1->a = 7;
}
void modifyMe2(struct myStructure **param1) {
(*param1)->a = 7;
}
int main(int argc, char *argv[]) {
struct myStructure *test1;
test1 = malloc(sizeof(test1));
test1->a = 5;
test1->b = 6;
modifyMe1(test1);
printf("a: %d, b: %d\n", test1->a, test1->b);
//set it back to 5
test1->a = 5;
printf("reset. a: %d, b: %d\n", test1->a, test1->b);
modifyMe2(&test1);
printf("a: %d, b: %d\n", test1->a, test1->b);
free(test1);
return 0;
}
In dem meine Ausgabe ist:
$ ./a
a: 7, b: 6
reset. a: 5, b: 6
a: 7, b: 6
- Sie können immer ändern, was ein Zeiger verweist. Jedoch, wie alle Dinge in C als Wert übergeben werden (Kopie), Sie können nicht ändern, die Funktion-argument, so dass der Anrufer sehen kann das ändern, es sei denn, Sie fügen Sie eine Ebene der Dereferenzierung. d.h., dieser code ändert nur die lokale Kopie;
void foo(int *p) { p = malloc(size); }
. - wenn Zeiger verwenden, dann übergeben, indem Zeiger, nicht nach Wert. Wenn die doppelten Zeiger, übergeben Sie die Adresse des Zeigers. Wenn Sie wollen, um pass " - Wert übergeben, ohne jegliche Hinweise.
- Ich meine nicht zu pedantisch sein, aber diese Frage scheint zu verwirren, alle Anfänger, alles, was in C durch Wert übergeben wird. Enthält Zeiger als gut.
- Ja, das ist verwirrend, denn wenn Sie an Wert von etwas, das nicht ist ein Zeiger heißt es pass-by-value, und geben Sie den Wert des Zeigers, dies wird als pass-by-Zeiger.
- Ich habe noch nie den Begriff "pass-by-pointer". Ich denke, es ist mehr einfach nur verstehen, dass, in C, alles von Wert übergeben wird. Zeiger sind nichts besonderes in keiner Weise.
- Hi Ed, werden Sie sagen, dass mit einer Doppel-Zeiger als argument erlaubt es uns, um die Adresse zu ändern, was er momentan zeigt? Ich denke, ich bin nicht klar, was der "Umweg" bedeutet... :-\
- Ich habe festgestellt, dass dies Begriffe, die in verschiedenen Büchern. Ich denke, dass es in jeder Sprache, wo-stack verwendet wird alles, was von Wert übergeben wird. Zum Beispiel, in Java gibt es pass-by-value und pass-by-reference beim kopieren der Wert oder die Adresse auf den stack geschoben wird, und diese Terminologie ist weit verbreitet...
- Es erlaubt Ihnen, zu ändern, was die Zeiger pooints, ja. In diesem Fall verweist es auf die ein Zeiger zeigt, so dass Sie ändern können, ist es Wert (also eine Adresse) und der Anrufer sehen die änderung, weil Sie geändert werden, dass der Speicher direkt.
- Ich bin mir nicht sicher, was es zu tun hat mit dem stack, die eine Implementierung detail, wie die einheimischen gespeichert sind. Die Skillung gar nicht erwähnen, einem "stack", nur variable Lebensdauer. Java hat auch einen stack. C# hat einen Stapel. Das hat nichts damit zu tun, mit dem argument übergeben Semantik
- javadude.com/articles/passbyvalue.htm
Du musst angemeldet sein, um einen Kommentar abzugeben.
Können Sie pass-argument in unterschiedlicher Weise in C (Captain Obvious, ja).
Wert. Dann ist es kopiert zu stapeln. Also die Funktion hat lokale Kopie der variable in der Funktion frame. Änderungen argument nicht ändern übergebenen Wert. Es ist wie "nur Lesen" - Modus
Übergeben, indem Zeiger. Kopieren der Adresse der Variablen übergeben wird (also ja, es ist noch immer durch Wert übergeben, sondern übergeben Sie den Wert der Adresse, nicht der ganze argument). Also das ist wie "Lesen und schreiben" - Modus. Wie Sie kann der Zugriff auf die übergebene variable durch seine-Adresse, Sie kann verändern Sie den Wert für diese variable außerhalb der Funktion.
Aber! Sie kann immer noch nicht ändern Zeiger.
Also, wenn Sie ändern möchten Zeiger, dann sollten Sie pass Zeiger auf Zeiger. Das ist wie "Lesen-schreiben ändern" - Modus:
Wenn das war nur Zeiger dann wäre es ja ein memory leak:
weil hier ordnen Sie die neue Adresse der lokalen Kopie der Adresse aus, und dieses argument zerstört werden würde nach der Funktion Abschluss.
UPD. Zum Beispiel haben wir
innerhalb der Funktion Speicherplatz reserviert und der Zeiger zugeordnet ist, die lokale variable. Anrufer hält immer noch den alten Wert. Nach dem Funktionsaufruf verlieren wir die Adresse von dem Speicher, so kann es nicht veröffentlicht werden.
Kurzes Fazit: es gibt eine einfache Regel - wenn nötig-zu ändern argument, pass Zeiger darauf. Also, wenn Sie möchten, zu ändern, Zeiger, übergeben Zeiger auf Zeiger. Wenn Sie wollen, Doppel-Wechsel-Zeiger übergeben Zeiger auf Zeiger auf Zeiger.
Passing argument von pointer ist auch viel schneller, weil Sie nicht brauchen, um kopieren Sie alle Wert auf dem stack (natürlich, wenn der Wert größer ist als Zeiger auf diesen Wert, ansonsten übergeben, indem Zeiger für die read-only ist sinnlos). Aber es ist gefährlich, weil es könnte geändert werden, innerhalb der Funktion. So können Sie sicher argument definieren Sie mit dem Schlüsselwort const
Dies ist wirklich hilfreich, wenn Sie die Arbeit mit 3rd-party-Bibliotheken: Funktion Unterschrift erfahren Sie, ob die Funktion ändern kann, ist dein argument oder nicht. Obwohl const ist optional, ist es angebracht zu schreiben Schlüsselwort const jeder Zeit ist es möglich
Array übergeben. In der Regel sendet auch array-Größe (daher, size_t) als argument. Array als Zeiger.
Manchmal findet man code, in dem Entwickler sendet Zeiger auf Objekt statt array, zum Beispiel
In diesem Fall array mit einem element und Zeiger-auf-element Verhalten sich ähnlich (obwohl, Sie sind nicht das gleiche).
mit einem normalen parameter, sagen
int
erhalten Sie eine lokale Kopiemit einem Zeiger-parameter, sagen
int*
können Sie ändern, was es Punktemit einem Doppel-pointer-parameter, sagen
int**
können Sie ändern, der pointer selbst, dh 'repoint' es.Fügen Sie eine weitere Funktion:
Dieser geht die Struktur durch einen Wert. Die änderung in der Funktion ist, spiegelt sich nicht in dem argument übergeben
modifyMe0()
.Hinzufügen aufrufende code wie dieser:
Beachten Sie, dass die vorher-und nachher-Werte im aufrufenden code sind die gleichen. Man könnte auch hinzufügen, drucken auf Ihrem
modifyMeN()
Funktionen, um zu demonstrieren, dass in Ihnen der Wert geändert wird.Wenn Sie übergeben einen Zeiger auf die Struktur, die an die aufgerufene Funktion den Wert der Struktur, in der aufrufenden Funktion geändert werden kann. Wenn Sie übergeben Sie die Struktur der aufgerufenen Funktion als Wert, der Wert der Struktur, in der aufrufenden Funktion nicht verändert wird.
Können Sie eine andere Funktion:
Hinzufügen aufrufende code wie dieser:
Beachten Sie, dass die Adresse der Struktur hat sich verändert nach dem Aufruf
modifyMe3()
.