C-Programmierung - Pass-by-Reference
-
26-09-2019 - |
Frage
In dem C-Programm unten, ich verstehe nicht, warum buf [0] = 'A', nachdem ich nenne foo. Ist das nicht Foopass-by-Wert zu tun?
#include <stdio.h>
#include <stdlib.h>
void foo(char buf[])
{
buf[0] = 'A';
}
int main(int argc, char *argv[])
{
char buf[10];
buf[0] = 'B';
printf("before foo | buf[0] = %c\n", buf[0]);
foo(buf);
printf("after foo | buf[0] = %c\n", buf[0]);
system("PAUSE");
return 0;
}
Ausgabe:
before foo | buf[0] = 'B'
after foo | buf[0] = 'A'
Lösung
void foo(char buf[])
ist die gleiche wie
void foo(char* buf)
Wenn Sie es nennen, foo(buf)
Sie einen Zeiger nach Wert übergeben, so dass eine Kopie des Zeigers gemacht wird.
Die Kopie der Zeiger auf dasselbe Objekt wie der ursprünglichen Zeiger (oder, in diesem Fall in das Ausgangselement des Arrays).
C nicht über Pass von Referenzsemantik in dem Sinne, dass C ++ Pass von Referenzsemantik hat. Alles in C wird durch Wert übergeben. Zeiger werden verwendet Pass von Referenzsemantik zu erhalten.
Andere Tipps
ein Array ist nur eine andere Art einen Zeiger zu verwenden. Wenn Sie buf
an die Funktion übergeben, die Sie vorbei ein Zeiger nach Wert, aber wenn Sie den Zeiger dereferenzieren, sie ist immer noch die Zeichenfolge verweisen darauf verweist.
Array als Funktionsparameter entspricht einen Zeiger, so dass die Erklärung
void foo( char buf[] );
ist die gleiche wie
void foo( char* buf );
Das Array Argument ist dann verfallene , um den Zeiger auf das erste Element.
Arrays sind anders als andere Arten behandelt; Sie können kein Array „von Wert“ in C
übergebenOnline C99-Standard (Entwurf n1256) , Abschnitt 6.3.2.1, "Lvalues, Arrays und Funktion Bezeich" Absatz 3:
außer wenn es der Operand des sizeof-Operator ist oder der unäre Operator &, oder ist eine Stringliteral verwendet, um ein Array zu initialisieren, einen Ausdruck, der Typ ‚‚Array vom Typ‘besitzt‘ ist auf einen Ausdruck mit Typ ‚‚Zeiger auf Typ‘‘ umgewandelt, der auf den Anfangs-Element das Array-Objekt und nicht ein L-Wert. Wenn das Array-Objekt hat Registerspeicherklasse, die Verhalten ist nicht definiert.
Im Aufruf
foo(buf);
der Array Ausdruck buf
ist nicht der Operand sizeof
oder &
, noch ist es ein Stringliteral verwendet wird um einen Array zu initialisieren, so dass es implizit konvertiert wird ( „Zerfälle“) vom Typ „10-Element-Array von char“ zu „Zeiger auf char“ und die Adresse des ersten Elements auf foo übergeben. Deshalb alles, was Sie buf
in foo()
tun wird in der buf
Array in main()
widerspiegeln. Weil, wie Array Subskribierung definiert ist, können Sie einen Index-Operator auf einem Zeigertyp verwenden, damit es Aussehen , wie Sie mit einem Array-Typ arbeiten, aber du bist nicht.
Im Rahmen einer Funktion Parameterdeklaration, T a[]
und T a[N]
sind gleichbedeutend mit T *a
, aber das ist nur Fall, dass das wahr ist.
* char buf [] bedeutet eigentlich char **, so dass Sie durch Zeiger / reference sind vorbei. Das gibt Ihnen die buf ist ein Zeiger, die beide in der Haupt () und foo () Funktion.
Weil Sie einen Zeiger auf buf
(nach Wert) sind vorbei. So ist der Inhalt von buf
geändert wird darauf wird.
Mit Zeiger ist es anders; Sie werden von Wert vorbei, aber was Sie vorbei ist der Wert des Zeigers, die nicht der gleiche wie der Wert des Arrays ist.
So wird der Wert des Zeigers ändert sich nicht, aber du bist zu modifizieren, was es zeigt auf.
Arrays und Zeiger sind (fast) die gleiche.
int* foo = malloc(...)
foo[2]
ist die gleiche wie *(foo+2*sizeof(int))
Anekdote: Sie schrieb
int main(int argc, char *argv[])
es auch legal ist (kompiliert und die gleiche Arbeit) zu schreiben
int main(int argc, char **argv)
und auch
int main(int argc, char argv[][])
Sie sind effektiv gleich. seine etwas kompliziert mehr als das, weil ein Array weiß, wie viele Elemente hat, und einen Zeiger nicht. aber sie sind die gleichen verwendet.
, um passieren, dass nach Wert, würde die Funktion muß die Größe des Arguments kennen. In diesem Fall sind vorbei Sie nur einen Zeiger.
Sie sind hier durch Verweis übergeben. In diesem Beispiel können Sie das Problem, indem ein einzelnes Zeichen auf dem Index des Arrays lösen gewünscht wird.
Wenn Sie den Inhalt des ursprünglichen Arrays erhalten möchten, können Sie die Zeichenfolge in den temporären Speicher in der Funktion kopieren.
edit: Was würde passieren, wenn Sie Ihren char-Array in einer Struktur gewickelt und die Struktur übergeben? Ich glaube auch, dass die Macht der Arbeit, obwohl ich nicht weiß, welche Art von Overhead, der auf der Compiler-Ebene erstellen kann.
Beachten Sie eine Sache,
Erklärung
void foo(char buf[])
sagt, dass wird mit [] Notation. Nicht, welches Element des Arrays werden Sie verwenden.
, wenn Sie darauf hinweisen möchten, wollen Sie etwas bestimmten Wert erhalten, dann sollten Sie diese Funktion erklären, wie
void foo(char buf[X]); //where X would be a constant.
Natürlich ist es nicht möglich, weil es sinnlos wäre (Funktion für bei n-te Elemente von Array-Betrieb?). Sie müssen nicht nach unten Informationen schreiben, das Element des Arrays Sie erhalten möchten. Alles, was Sie brauchen, ist einfache Erklärung:
voi foo(char value);
so ...
void foo(char buf[])
ist eine Erklärung, die besagt, welche Schreibweise Sie verwenden möchten. ([] - Teil), und es enthält auch Zeiger auf einige Daten
Außerdem ... was würden Sie erwarten ... gesendet Sie Funktion foo einen Namen array
foo(buf);
, die zu & buf entspricht [0]. Also ... das ist ein Zeiger.
Arrays in C nicht von Wert übergeben. Sie sind nicht einmal legitime Funktionsparameter. Stattdessen sieht der Compiler, dass Sie ein Array passieren sind versucht und degradiert sie zu Zeiger. Er tut dies, still, weil es böse. Es mag auch Kick Welpen.
Arrays in Funktionsparametern zu verwenden ist eine schöne Art und Weise zu Ihrem API-Benutzer zu signalisieren, dass dieses Ding ein Speicherblock sein sollte segmentierte in n-Byte-Stücke bemessen, aber nicht erwarten, Compiler zu kümmern, wenn Sie char *foo
char foo[]
oder char foo[12]
buchstabieren in Funktionsparametern. Das werden sie nicht.