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'
War es hilfreich?

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

übergeben

Online 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.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top