Beim Umgang mit Arrays und Funktionen gibt es ein Muster. es ist zunächst nur ein wenig schwer zu sehen.
Beim Umgang mit Arrays ist Folgendes zu beachten: Wenn in den meisten Kontexten ein Array-Ausdruck angezeigt wird, wird der Typ des Ausdrucks implizit von "N-Element-Array von T" in "Zeiger auf T" konvertiert und sein Wert festgelegt um auf das erste Element im Array zu zeigen. Die Ausnahmen von dieser Regel sind , wenn der Array Ausdruck erscheint als Operanden entweder die &
oder sizeof
Betreiber, oder wenn es ein Stringliteral als Initialisierer in einer Erklärung verwendet wird.
Wenn Sie also eine Funktion mit einem Array-Ausdruck als Argument aufrufen, erhält die Funktion einen Zeiger und kein Array:
int arr[10];
...
foo(arr);
...
void foo(int *arr) { ... }
Dies ist , warum Sie nicht die Verwendung &
auf „% s“ entsprechenden Operator für Argumente scanf()
:
char str[STRING_LENGTH];
...
scanf("%s", str);
scanf()
Empfängt aufgrund der impliziten Konvertierung einen char *
Wert, der auf den Anfang des str
Arrays zeigt. Dies gilt für jede Funktion mit einem Array Ausdruck als Argument (nur über eine der genannten str*
Funktionen *scanf
und *printf
Funktionen, etc.).
In der Praxis werden Sie wahrscheinlich niemals eine Funktion mit einem Array-Ausdruck mit dem &
Operator aufrufen , wie in:
int arr[N];
...
foo(&arr);
void foo(int (*p)[N]) {...}
Ein solcher Code ist nicht sehr verbreitet; Sie müssen die Größe des Arrays in der Funktionsdeklaration kennen, und die Funktion funktioniert nur mit Zeigern auf Arrays bestimmter Größe (ein Zeiger auf ein Array mit 10 Elementen von T ist ein anderer Typ als ein Zeiger auf ein Array mit 11 Elementen von T).
Wenn ein Array-Ausdruck als Operand für den &
Operator angezeigt wird , ist der Typ des resultierenden Ausdrucks "Zeiger auf N-Element-Array von T" oder T (*)[N]
unterscheidet sich von einem Array von Zeigern ( T *[N]
) und einem Zeiger auf den Basistyp (). T *
).
Beim Umgang mit Funktionen und Zeigern gilt folgende Regel: Wenn Sie den Wert eines Arguments ändern und im aufrufenden Code wiedergeben möchten, müssen Sie einen Zeiger auf das Element übergeben, das Sie ändern möchten. Wieder werfen Arrays einen kleinen Schraubenschlüssel in die Werke, aber wir werden uns zuerst mit den normalen Fällen befassen.
Denken Sie daran, dass C alle Funktionsargumente als Wert übergibt . Der formale Parameter erhält eine Kopie des Werts im tatsächlichen Parameter, und Änderungen am formalen Parameter werden nicht im tatsächlichen Parameter berücksichtigt. Das häufigste Beispiel ist eine Swap-Funktion:
void swap(int x, int y) { int tmp = x; x = y; y = tmp; }
...
int a = 1, b = 2;
printf("before swap: a = %d, b = %d\n", a, b);
swap(a, b);
printf("after swap: a = %d, b = %d\n", a, b);
Sie erhalten folgende Ausgabe:
vor dem Tausch: a = 1, b = 2
nach dem Tausch: a = 1, b = 2
Die formalen Parameter x
und y
sind verschiedene Objekte von a
undb
, daher ändern sich Änderungen an x
und y
werden nicht in a
und wiedergegeben b
. Da wir die Werte von a
und ändern möchten b
, müssen wir Zeiger darauf an die Swap-Funktion übergeben:
void swap(int *x, int *y) {int tmp = *x; *x = *y; *y = tmp; }
...
int a = 1, b = 2;
printf("before swap: a = %d, b = %d\n", a, b);
swap(&a, &b);
printf("after swap: a = %d, b = %d\n", a, b);
Jetzt wird Ihre Ausgabe sein
vor dem Tausch: a = 1, b = 2
nach dem Tausch: a = 2, b = 1
Beachten Sie, dass wir in der Swap-Funktion nicht die Werte von x
und ändern y
, sondern die Werte von whatx
und y
zeigen auf . Schreiben an *x
unterscheidet sich vom Schreiben an x
; Wir aktualisieren den Wert nicht an x
sich, wir erhalten einen Speicherort von x
und aktualisieren den Wert an diesem Speicherort.
Dies gilt auch, wenn wir einen Zeigerwert ändern möchten. wenn wir schreiben
int myFopen(FILE *stream) {stream = fopen("myfile.dat", "r"); }
...
FILE *in;
myFopen(in);
dann ändern wir den Wert des Eingabeparameters stream
, nicht wasstream
ändern zeigt. Eine Änderung stream
hat also keine Auswirkung auf den Wert von in
. Damit dies funktioniert, müssen wir einen Zeiger auf den Zeiger übergeben:
int myFopen(FILE **stream) {*stream = fopen("myFile.dat", "r"); }
...
FILE *in;
myFopen(&in);
Auch hier werfen Arrays einen kleinen Schraubenschlüssel in die Werke. Wenn Sie einen Array-Ausdruck an eine Funktion übergeben, empfängt die Funktion einen Zeiger. Aufgrund der Definition der Array-Subskription können Sie einen Indexoperator für einen Zeiger genauso verwenden wie für ein Array:
int arr[N];
init(arr, N);
...
void init(int *arr, int N) {size_t i; for (i = 0; i < N; i++) arr[i] = i*i;}
Beachten Sie, dass Array-Objekte möglicherweise nicht zugewiesen werden. dh du kannst so etwas nicht machen
int a[10], b[10];
...
a = b;
Sie sollten also vorsichtig sein, wenn Sie mit Zeigern auf Arrays arbeiten. etwas wie
void (int (*foo)[N])
{
...
*foo = ...;
}
wird nicht funktionieren.