Referenzübergabe in C

Lesezeit: 7 Minuten

Benutzeravatar von aks
fragt

Wenn C die Übergabe einer Variablen als Referenz nicht unterstützt, warum funktioniert das?

#include <stdio.h>

void f(int *j) {
  (*j)++;
}

int main() {
  int i = 20;
  int *p = &i;
  f(p);
  printf("i = %d\n", i);

  return 0;
}

Ausgabe:

$ gcc -std=c99 test.c
$ a.exe
i = 21 

  • Wo in diesem Code passieren Sie Hinweis?

    – Atul

    27. Februar 2015 um 2:42 Uhr

  • Es sollte beachtet werden, dass C keine Pass by Reference hat, es kann nur sein emuliert Zeiger verwenden.

    – Irgendein Programmierer-Typ

    9. März 2016 um 13:05 Uhr

  • Die korrekte Aussage lautet: „C unterstützt nicht implizit Übergabe einer Variablen als Referenz” – Sie müssen explizit eine Referenz erstellen (mit &) vor dem Aufruf der Funktion und explizit dereferenzieren (with *) in der Funktion.

    – Chris Dodd

    26. Mai 2017 um 18:49 Uhr


  • Ihre Codeausgabe entspricht genau dem Aufruf f(&i); Dies ist eine Implementierung von Pass-by-Reference, die in CC-Pass-by-Reference nicht existiert

    – EsmaeelE

    9. Januar 2019 um 21:33 Uhr


  • @Someprogrammerdude Das Übergeben eines Zeigers ist eine Referenzübergabe. Dies scheint eine dieser Tatsachen zu sein, auf die “versierte” C-Programmierer stolz sind. Als hätten sie einen Kick davon. “Oh, Sie denken vielleicht, C hat Pass-by-Reference, aber nein, es ist eigentlich nur der Wert einer Speicheradresse, die übergeben wird, harharhar.” Das Übergeben per Referenz bedeutet buchstäblich nur das Übergeben der Speicheradresse, an der eine Variable gespeichert ist, und nicht des Wertes der Variablen selbst. Das ist es, was C zulässt, und es ist jedes Mal eine Referenzübergabe, wenn Sie einen Zeiger übergeben, weil ein Zeiger a ist Hinweis an einen Variablenspeicherort.

    – ICW

    21. August 2019 um 18:19 Uhr


Benutzeravatar von tvanfosson
tvanfosson

Weil du vorbeigehst der Wert des Zeigers auf die Methode und deren Dereferenzierung, um die Ganzzahl zu erhalten, auf die gezeigt wird.

  • f(p); -> Bedeutet dies, dass der Wert übergeben wird? dann dereferenzieren, um die Ganzzahl zu erhalten, auf die gezeigt wird. -> Könnten Sie bitte mehr Erklärung geben.

    – bap

    4. März 2014 um 13:02 Uhr

  • @bapi, das Dereferenzieren eines Zeigers bedeutet, “den Wert zu erhalten, auf den dieser Zeiger verweist”.

    – Rauni Lillemets

    11. November 2014 um 13:35 Uhr

  • Was wir für die Methode zum Aufrufen der Funktion aufrufen, die die Adresse der Variablen übernimmt, anstatt den Zeiger zu übergeben. Beispiel: func1(int &a) . Ist das kein Call by Reference? In diesem Fall wird die Referenz wirklich genommen und im Falle eines Zeigers übergeben wir immer noch den Wert, da wir den Zeiger nur als Wert übergeben.

    – Jon Wheelock

    10. Oktober 2015 um 17:14 Uhr


  • Bei der Verwendung von Zeigern ist dies die entscheidende Tatsache Kopie des Zeigers wird an die Funktion übergeben. Die Funktion verwendet dann diesen Zeiger, nicht den ursprünglichen. Dies ist immer noch Pass-by-Value, aber es funktioniert.

    – Daniel

    18. November 2016 um 10:24 Uhr


  • @Danijel Es ist möglich, einen Zeiger, der keine Kopie von irgendetwas ist, an einen Funktionsaufruf zu übergeben. Zum Beispiel das Aufrufen der Funktion func: func(&A); Dies würde einen Zeiger auf A an die Funktion übergeben, ohne irgendetwas zu kopieren. Es handelt sich um eine Wertübergabe, aber dieser Wert ist eine Referenz, sodass Sie die Variable A “durch Referenz übergeben”. Kein Kopieren erforderlich. Es ist gültig zu sagen, dass es Pass-by-Reference ist.

    – ICW

    18. September 2019 um 18:27 Uhr


Elys Benutzeravatar
Ely

Das ist keine Pass-by-Reference, das ist Pass-by-Value, wie andere sagten.

Die C-Sprache ist ausnahmslos Pass-by-Value. Die Übergabe eines Zeigers als Parameter bedeutet keine Referenzübergabe.

Die Regel ist folgende:

Eine Funktion ist nicht in der Lage, den tatsächlichen Parameterwert zu ändern.

(Das obige Zitat stammt eigentlich aus dem Buch K&R)


Versuchen wir, die Unterschiede zwischen Skalar- und Zeigerparametern einer Funktion zu sehen.

Skalare Variablen

Dieses kurze Programm zeigt Pass-by-Value unter Verwendung einer skalaren Variablen. param heißt Formalparameter und variable beim Funktionsaufruf heißt aktueller Parameter. Beachten Sie die Erhöhung param an der Funktion ändert sich nichts variable.

#include <stdio.h>

void function(int param) {
    printf("I've received value %d\n", param);
    param++;
}

int main(void) {
    int variable = 111;

    function(variable);
    printf("variable %d\m", variable);
    return 0;
}

Das Ergebnis ist

I've received value 111
variable=111

Illusion der Pass-by-Referenz

Wir ändern den Code leicht. param ist jetzt ein Zeiger.

#include <stdio.h>

void function2(int *param) {
    printf("I've received value %d\n", *param);
    (*param)++;
}

int main(void) {
    int variable = 111;

    function2(&variable);
    printf("variable %d\n", variable);
    return 0;
}

Das Ergebnis ist

I've received value 111
variable=112

Das lässt Sie glauben, dass der Parameter als Referenz übergeben wurde. Es war nicht. Es wurde als Wert übergeben, wobei der Parameterwert eine Adresse ist. Der Wert des int-Typs wurde inkrementiert, und das ist der Nebeneffekt, der uns denken lässt, dass es sich um einen Pass-by-Reference-Funktionsaufruf handelte.

Zeiger – als Wert übergeben

Wie können wir diese Tatsache zeigen/beweisen? Nun, vielleicht können wir das erste Beispiel von skalaren Variablen ausprobieren, aber anstelle von skalaren verwenden wir Adressen (Zeiger). Mal sehen, ob das helfen kann.

#include <stdio.h>

void function2(int *param) {
    printf("address param is pointing to %d\n", param);
    param = NULL;
}

int main(void) {
    int variable = 111;
    int *ptr = &variable;

    function2(ptr);
    printf("address ptr is pointing to %d\n", ptr);
    return 0;
}

Das Ergebnis wird sein, dass die beiden Adressen gleich sind (machen Sie sich keine Gedanken über den genauen Wert).

Beispielergebnis:

address param is pointing to -1846583468
address ptr   is pointing to -1846583468

Meiner Meinung nach beweist dies eindeutig, dass Zeiger als Wert übergeben werden. Andernfalls ptr wäre NULL nach Funktionsaufruf.

  • “ptr’s address” ist nicht korrekt: Sie drucken den Zeiger, der die Adresse der Variablen ist, nicht ihre Adresse, das wäre ´printf(“ptr’s address %d\n”, &ptr);´ . Die technische Ebene des Übergebens einer Referenz ist das Übergeben eines Zeigers, keine Illusion! In Funktion2 ist *param tatsächlich eine Referenz.

    – Sam Ginrich

    25. Februar um 8:24 Uhr

  • Richtig. Was im Teil „Zeiger – Wertübergabe“ gezeigt wird, sollte eigentlich umformuliert werden in: „printf(“where pointer param is pointing to %d\n“, param);“ und “printf(“wo der Zeiger ptr auf %d\n zeigt”, ptr);”. Gut erwischt^^ Und ich denke, was angezeigt werden sollte, ist tatsächlich: “printf(“pointer params address %d\n”, &param);” und “printf(“Zeiger ptrs Adresse %d\n”, &ptr);”

    – Daniel

    4. April um 16:59 Uhr


  • Ja, du hast recht. Ich korrigiere das. Tatsächlich wollte ich zeigen, dass die Adressen, auf die sie verweisen, dieselben sind. Die Adressen der Pointer sind hier nicht wirklich interessant (und nicht gleich).

    – Eli

    4. April um 19:18 Uhr


In C wird Pass-by-Reference simuliert, indem die Adresse einer Variablen (eines Zeigers) übergeben und diese Adresse innerhalb der Funktion dereferenziert wird, um die eigentliche Variable zu lesen oder zu schreiben. Dies wird als “Pass-by-Reference im C-Stil” bezeichnet.

Quelle: www-cs-students.stanford.edu

Benutzeravatar von Alexander Gessler
Alexander Geßler

Weil es im obigen Code keine Pass-by-Referenz gibt. Mit Zeigern (wie z void func(int* p)) ist eine Pass-by-Adresse. Dies ist Pass-by-Reference in C++ (funktioniert nicht in C):

void func(int& ref) {ref = 4;}

...
int a;
func(a);
// a is 4 now

Benutzeravatar von Daniel Vassallo
Daniel Wassallo

Ihr Beispiel funktioniert, weil Sie die Adresse Ihrer Variablen an eine Funktion übergeben, die ihren Wert mit manipuliert Dereferenzierungsoperator.

Während C nicht unterstützt Referenzdatentypenkönnen Sie dennoch die Referenzübergabe simulieren, indem Sie wie in Ihrem Beispiel Zeigerwerte explizit übergeben.

Der C++-Referenzdatentyp ist weniger leistungsfähig, gilt aber als sicherer als der von C geerbte Zeigertyp. Dies wäre Ihr Beispiel, angepasst an die Verwendung C++-Referenzen:

void f(int &j) {
  j++;
}

int main() {
  int i = 20;
  f(i);
  printf("i = %d\n", i);

  return 0;
}

  • Dieser Wikipedia-Artikel handelt von C++, nicht von C. Referenzen existierten vor C++ und sind nicht von einer speziellen C++-Syntax abhängig.

    Roger Pate

    10. Februar 2010 um 3:52 Uhr

  • @ Roger: Guter Punkt … Ich habe den expliziten Verweis auf C ++ aus meiner Antwort entfernt.

    – Daniel Vasallo

    10. Februar 2010 um 8:44 Uhr

  • Und in diesem neuen Artikel heißt es: “Eine Referenz wird oft als Zeiger bezeichnet”, was nicht ganz das ist, was Ihre Antwort sagt.

    Roger Pate

    10. Februar 2010 um 16:13 Uhr

Sie passieren a Zeiger(Adresse Ort) nach Wert.

Es ist, als würde man sagen: „Hier ist der Ort mit den Daten, die Sie aktualisieren sollen.“

  • Dieser Wikipedia-Artikel handelt von C++, nicht von C. Referenzen existierten vor C++ und sind nicht von einer speziellen C++-Syntax abhängig.

    Roger Pate

    10. Februar 2010 um 3:52 Uhr

  • @ Roger: Guter Punkt … Ich habe den expliziten Verweis auf C ++ aus meiner Antwort entfernt.

    – Daniel Vasallo

    10. Februar 2010 um 8:44 Uhr

  • Und in diesem neuen Artikel heißt es: “Eine Referenz wird oft als Zeiger bezeichnet”, was nicht ganz das ist, was Ihre Antwort sagt.

    Roger Pate

    10. Februar 2010 um 16:13 Uhr

Benutzeravatar von Pavel Radzivilovsky
Pavel Radzivilovsky

Keine Referenzübergabe in C, aber p “verweist” auf i, und Sie übergeben p als Wert.

1426220cookie-checkReferenzübergabe in C

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy