Übergeben eines Arrays als Argument an eine Funktion in C.

86

Ich habe eine Funktion geschrieben, die ein Array als Argument enthält, und sie aufgerufen, indem ich den Wert des Arrays wie folgt übergeben habe.

void arraytest(int a[])
{
    // changed the array a
    a[0]=a[0]+a[1];
    a[1]=a[0]-a[1];
    a[0]=a[0]-a[1];
}

void main()
{
    int arr[]={1,2};
    printf("%d \t %d",arr[0],arr[1]);
    arraytest(arr);
    printf("\n After calling fun arr contains: %d\t %d",arr[0],arr[1]);
}

Was ich gefunden habe, ist, dass ich die arraytest()Funktion aufrufe, indem ich Werte übergebe, die Originalkopie vonint arr[] geändert aufrufe.

Können Sie bitte erklären, warum?

Mohan Mahajan
quelle
1
Sie übergeben das Array als Referenz, aber Sie ändern seinen Inhalt - daher sehen Sie eine Änderung in den Daten
Shaun Wilde
main()muss zurückkehren int.
underscore_d

Antworten:

137

Wenn Sie ein Array als Parameter übergeben, ist dies

void arraytest(int a[])

bedeutet genau das gleiche wie

void arraytest(int *a)

so Sie sind Modifizieren der Werte in main.

Aus historischen Gründen sind Arrays keine erstklassigen Bürger und können nicht wertmäßig weitergegeben werden.

Bo Persson
quelle
3
Welche Notation ist unter welchen Umständen besser?
Ramon Martinez
19
@Ramon - Ich würde die zweite Option verwenden, da sie weniger verwirrend erscheint und besser darauf hinweist, dass Sie keine Kopie des Arrays erhalten.
Bo Persson
2
Können Sie die "historischen Gründe" erklären? Ich nehme an, das Übergeben von Werten würde eine Kopie und damit eine Verschwendung von Speicher erfordern. Danke
Jacquelyn.Marquardt
5
@lucapozzobon - Ursprünglich hatte C außer einzelnen Werten keinen Wert für die Übergabe. Erst als structder Sprache hinzugefügt wurde, wurde dies geändert. Und dann wurde es als zu spät angesehen, die Regeln für Arrays zu ändern. Es gab bereits 10 Benutzer. :-)
Bo Persson
1
... bedeutet genau das Gleiche wie void arraytest(int a[1000])usw. usw. Erweiterte Antwort hier: stackoverflow.com/a/51527502/4561887 .
Gabriel Staples
9

Wenn Sie ein eindimensionales Array als Argument in einer Funktion übergeben möchten, müssen Sie einen formalen Parameter auf eine der folgenden drei Arten deklarieren. Alle drei Deklarationsmethoden führen zu ähnlichen Ergebnissen, da jeder dem Compiler mitteilt, dass ein ganzzahliger Zeiger ausgeführt wird empfangen werden .

int func(int arr[], ...){
    .
    .
    .
}

int func(int arr[SIZE], ...){
    .
    .
    .
}

int func(int* arr, ...){
    .
    .
    .
}

Sie ändern also die ursprünglichen Werte.

Vielen Dank !!!

Monirul Islam Milon
quelle
Ich habe nach Ihrem zweiten Beispiel gesucht. Können Sie die Vorteile der einzelnen Methoden erläutern?
Puck
8

Sie übergeben das Array nicht als Kopie. Es ist nur ein Zeiger, der auf die Adresse zeigt, an der sich das erste Element des Arrays im Speicher befindet.

fyr
quelle
7

Sie übergeben die Adresse des ersten Elements des Arrays

ob_dev
quelle
7

Arrays in C werden in den meisten Fällen in einen Zeiger auf das erste Element des Arrays selbst konvertiert. Und detailliertere Arrays, die an Funktionen übergeben werden, werden immer in Zeiger konvertiert.

Hier ein Zitat von K & R2nd :

Wenn ein Array-Name an eine Funktion übergeben wird, wird die Position des Anfangselements übergeben. Innerhalb der aufgerufenen Funktion ist dieses Argument eine lokale Variable, und daher ist ein Array-Name-Parameter ein Zeiger, dh eine Variable, die eine Adresse enthält.

Schreiben:

void arraytest(int a[])

hat die gleiche Bedeutung wie das Schreiben:

void arraytest(int *a)

Obwohl Sie es nicht explizit schreiben, ist es so, als würden Sie einen Zeiger übergeben und die Werte im Main ändern.

Weiter Ich schlage vor , das Lesen wirklich diese .

Darüber hinaus können Sie andere Antworten SO finden auf hier

Granmirupa
quelle
6

Sie übergeben den Wert des Speicherorts des ersten Mitglieds des Arrays.

Wenn Sie also mit dem Ändern des Arrays innerhalb der Funktion beginnen, ändern Sie das ursprüngliche Array.

Denken Sie daran, das a[1]ist *(a+1).

Alex
quelle
1
Ich nehme an, es fehlen () für * a + 1 sollte * (a + 1) sein
ShinTakezou
@ Shin Danke, es ist schon eine Weile her, seit ich mit C. gespielt habe
Alex
6

In C "zerfällt" eine Array-Referenz mit Ausnahme einiger Sonderfälle immer auf einen Zeiger auf das erste Element des Arrays. Daher ist es nicht möglich, ein Array "nach Wert" zu übergeben. Ein Array in einem Funktionsaufruf wird als Zeiger an die Funktion übergeben, was analog zum Übergeben des Arrays als Referenz ist.

BEARBEITEN: Es gibt drei solche Sonderfälle, in denen ein Array nicht in einen Zeiger auf sein erstes Element zerfällt:

  1. sizeof aist nicht dasselbe wie sizeof (&a[0]).
  2. &aist nicht dasselbe wie &(&a[0])(und nicht ganz dasselbe wie &a[0]).
  3. char b[] = "foo"ist nicht dasselbe wie char b[] = &("foo").
Thom Smith
quelle
Wenn ich ein Array an eine Funktion übergebe. Angenommen, ich habe ein Array erstellt int a[10]und jedem Element einen zufälligen Wert zugewiesen. Wenn ich dieses Array nun mit int y[]oder int y[10]oder an eine Funktion übergebe, verwende int *yich in dieser Funktion die sizeof(y)Antwort. Der Bytezeiger wurde zugewiesen. In diesem Fall wird es als Zeiger verfallen. Es wäre hilfreich, wenn Sie dies auch einschließen. Siehe diese postimg.org/image/prhleuezd
Suraj Jain
Wenn ich sizeofoperiere in der Funktion in dem ursprünglich definierten Array, dann wird es als Array zerfallen, aber wenn ich eine andere Funktion übergebe, dann wird dort der sizeofOperator als Zeiger zerfallen.
Suraj Jain
Ich weiß, dass das alt ist. Zwei Fragen, wenn jemand dies sieht :) 1. @ThomSmith hat geschrieben, dass dies &anicht ganz das gleiche ist wie &a[0]bei aeinem Array. Wieso das? In meinem Testprogramm sind beide gleich, sowohl in der Funktion, in der das Array deklariert ist, als auch wenn sie an eine andere Funktion übergeben werden. 2. Der Autor schreibt, dass " char b[] = "foo"nicht dasselbe ist wie char b[] = &("foo")". Letzteres kompiliert für mich nicht einmal. Ist es nur ich
Aviv Cohn
6

Übergeben eines mehrdimensionalen Arrays als Argument an eine Funktion. Das Übergeben eines One-Dim-Arrays als Argument ist mehr oder weniger trivial. Werfen wir einen Blick auf einen interessanteren Fall, bei dem ein 2-Dim-Array übergeben wird. In C können Sie keinen Zeiger auf das Zeigerkonstrukt ( int **) anstelle eines 2-Dim-Arrays verwenden. Machen wir ein Beispiel:

void assignZeros(int(*arr)[5], const int rows) {
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < 5; j++) {
            *(*(arr + i) + j) = 0;
            // or equivalent assignment
            arr[i][j] = 0;
        }
    }

Hier habe ich eine Funktion angegeben, die als erstes Argument einen Zeiger auf ein Array von 5 Ganzzahlen verwendet. Ich kann als Argument jedes 2-Dim-Array mit 5 Spalten übergeben:

int arr1[1][5]
int arr1[2][5]
...
int arr1[20][5]
...

Möglicherweise kommen Sie auf die Idee, eine allgemeinere Funktion zu definieren, die ein beliebiges 2-Dim-Array akzeptieren und die Funktionssignatur wie folgt ändern kann:

void assignZeros(int ** arr, const int rows, const int cols) {
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            *(*(arr + i) + j) = 0;
        }
    }
}

Dieser Code würde kompiliert, aber Sie erhalten einen Laufzeitfehler, wenn Sie versuchen, die Werte auf die gleiche Weise wie in der ersten Funktion zuzuweisen. In C sind mehrdimensionale Arrays also nicht dasselbe wie Zeiger auf Zeiger ... auf Zeiger. An int(*arr)[5]ist ein Zeiger auf ein Array von 5 Elementenint(*arr)[6] ist ein Zeiger auf ein Array von 6 Elementen und sie sind ein Zeiger auf verschiedene Typen!

Wie definiere ich Funktionsargumente für höhere Dimensionen? Einfach, wir folgen einfach dem Muster! Hier ist dieselbe Funktion, die für ein Array mit drei Dimensionen angepasst wurde:

void assignZeros2(int(*arr)[4][5], const int dim1, const int dim2, const int dim3) {
    for (int i = 0; i < dim1; i++) {
        for (int j = 0; j < dim2; j++) {
            for (int k = 0; k < dim3; k++) {
                *(*(*(arr + i) + j) + k) = 0;
                // or equivalent assignment
                arr[i][j][k] = 0;
            }
        }
    }
}

Wie zu erwarten, können 3 dim-Arrays als Argument verwendet werden, die in der zweiten Dimension 4 Elemente und in der dritten Dimension 5 Elemente enthalten. So etwas wäre in Ordnung:

arr[1][4][5]
arr[2][4][5]
...
arr[10][4][5]
...

Wir müssen jedoch alle Abmessungen bis zur ersten angeben.

Andrushenko Alexander
quelle
4

@ Bo Persson sagt in seiner großartigen Antwort hier richtig :

================================================

Wenn Sie ein Array als Parameter übergeben, ist dies

void arraytest(int a[])

bedeutet genau das gleiche wie

void arraytest(int *a)

================================================

Lassen Sie mich jedoch auch hinzufügen, dass es:

bedeutet genau das gleiche wie

void arraytest(int a[0])

was genau das gleiche bedeutet wie

void arraytest(int a[1])

was genau das gleiche bedeutet wie

void arraytest(int a[2])

was genau das gleiche bedeutet wie

void arraytest(int a[1000])

etc.

Tatsächlich dient der Wert "Größe" innerhalb des Array-Parameters anscheinend nur der Ästhetik / Selbstdokumentation und kann eine beliebige positive Ganzzahl ( size_tTyp, glaube ich) sein!

In der Praxis sollten Sie es jedoch verwenden, um die Mindestgröße des Arrays anzugeben, das die Funktion erhalten soll, damit Sie beim Schreiben von Code leicht nachverfolgen und überprüfen können. Der MISRA-C-2012- Standard ( kaufen / herunterladen Sie das PDF mit der 236-Seiten-Version 2012 des Standards für £ 15.00 hier ) geht so weit:

Regel 17.5 Das Funktionsargument, das einem Parameter entspricht, der als Array-Typ deklariert wurde, muss eine angemessene Anzahl von Elementen aufweisen.

...

Wenn ein Parameter als Array mit einer bestimmten Größe deklariert ist, sollte das entsprechende Argument in jedem Funktionsaufruf auf ein Objekt verweisen, das mindestens so viele Elemente wie das Array enthält.

...

Die Verwendung eines Array-Deklarators für einen Funktionsparameter gibt die Funktionsschnittstelle klarer an als die Verwendung eines Zeigers. Die Mindestanzahl der von der Funktion erwarteten Elemente wird explizit angegeben, während dies mit einem Zeiger nicht möglich ist. [Betonung hinzugefügt]

Mit anderen Worten, sie empfehlen die Verwendung des expliziten Größenformats, auch wenn der C-Standard dies technisch nicht erzwingt. Dies hilft Ihnen als Entwickler und anderen, die den Code verwenden, zumindest zu klären, welche Größenanordnung die Funktion erwartet Sie zu übergeben.

Gabriel Staples
quelle
1
void arraytest(int (*a)[1000])ist besser, weil dann der Compiler einen Fehler macht, wenn die Größe falsch ist.
Flügelspieler Sendon
-1

Arrays werden immer als Referenz übergeben, wenn Sie a[]oder verwenden *a:

int* printSquares(int a[], int size, int e[]) {   
    for(int i = 0; i < size; i++) {
        e[i] = i * i;
    }
    return e;
}

int* printSquares(int *a, int size, int e[]) {
    for(int i = 0; i < size; i++) {
        e[i] = i * i;
    }
    return e;
}
anil karikatti
quelle