2017-02-05 5 views
11

Im Allgemeinen, wenn wir Array durch seinen Namen übergeben, ist es Anruf von Adresse. Das heißt, wenn wir irgendeinen Wert des Arrays außerhalb von main() ändern, wird dies in main() widergespiegelt.Übergeben Sie ein Array nach Wert

Also, was soll ich tun, um, wenn ich will das Array als Argument einer Funktion zu übergeben und es in main() so nennen, dass jede Änderung in dieser Funktion nicht innerhalb main() widerspiegeln?

Zum Beispiel:

void Foo(int arr[]) //takes an integer array `arr` as argument 
{ 
    // do something with `arr 
} 

int main() 
{ 
    int abc[]={5,1,2,9}; 
    //do something to pass `abc` inside `Foo` so that changes inside `Foo` doesn't change the value of `abc` array. 
} 

Jetzt möchte ich die abc Array Foo nach Wert zu übergeben.

+6

Sie können es in einer Struktur wickeln, aber das ist ein bisschen wie ein Hack. Warum nicht 'memcpy' in' Foo' verwenden? – Ryan

+2

"*' // nimmt ein Integer Array arr als Argument an "*" Nun, nein, in der Tat braucht es ein 'int *'. Im Zusammenhang mit der Definition von Funktionsargumenten ist "T t []" äquivalent zu "T * t". – alk

Antwort

12

Dies ist möglich, indem das Array in eine struct verpackt wird. Sie können ein Feld für die Größe des Arrays einfügen, so dass Sie diesen Parameter nicht explizit übergeben müssen. Dieser Ansatz hat den Vorteil, dass zusätzliche Speicherzuordnungen vermieden werden, die später freigegeben werden müssen.

C übergibt bereits Argumente an Funktionen nach Wert, aber Arraybezeichner zerfallen in den meisten Ausdrücken und insbesondere in Funktionsaufrufen zu Zeigern. Doch struct s zerfallen nicht in Zeiger und werden als Wert an eine Funktion übergeben, was bedeutet, dass eine Kopie der ursprünglichen Struktur und aller ihrer Inhalte im Gültigkeitsbereich der Funktion sichtbar ist. Wenn die struct ein Array enthält, wird dies ebenfalls kopiert. Beachten Sie, dass der Zeiger stattdessen kopiert wird, wenn die struct an die Funktion übergeben wird, aber derselbe Speicher von der Kopie und dem ursprünglichen Zeiger referenziert wird, wenn stattdessen struct einen Zeiger auf int für ein dynamisches Array enthält.Dieser Ansatz basiert auf dem struct, der ein tatsächliches Array enthält.

Beachten Sie auch, dass struct kein Mitglied mit einem unvollständigen Typ enthalten kann und daher kein VLA enthalten kann. Hier habe ich die globale Konstante MAX_ARR als 100 definiert, um etwas Platz für die Handhabung unterschiedlich großer Arrays mit demselben Typ struct zu schaffen.

Sie können auch eine struct von einer Funktion zurückgeben. Ich habe ein Beispiel eingefügt, das die Arraystruct modifiziert, die in eine Funktion übergeben wird, und die modifizierte struct zurückgibt, die einem anderen Arraystruct in der aufrufenden Funktion zugewiesen wird. Dies führt dazu, dass der Aufrufer sowohl auf das ursprüngliche als auch das transformierte Array zugreifen kann.

#include <stdio.h> 

#define MAX_ARR 100 

struct Array { 
    size_t size; 
    int array[MAX_ARR]; 
}; 

void print_array(struct Array local_arr); 
void func(struct Array local_arr); 
struct Array triple(struct Array local_arr); 

int main(void) 
{ 
    struct Array data = { 
     .size = 10, 
     .array = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 } 
    }; 
    struct Array transformed_data; 

    func(data); 
    transformed_data = triple(data); 

    printf("Original\n"); 
    print_array(data); 

    printf("Transformed\n"); 
    print_array(transformed_data); 

    return 0; 
} 

void print_array(struct Array local_arr) 
{ 
    for (size_t i = 0; i < local_arr.size; i++) { 
     printf("%5d", local_arr.array[i]); 
    } 
    putchar('\n'); 
} 

void func(struct Array local_arr) 
{ 
    for (size_t i = 0; i < local_arr.size; i++) { 
     local_arr.array[i] *= 2; 
    } 
    printf("Modified\n"); 
    print_array(local_arr); 
} 

struct Array triple(struct Array local_arr) 
{ 
    for (size_t i = 0; i < local_arr.size; i++) { 
     local_arr.array[i] *= 3; 
    } 
    return local_arr; 
} 

Programmausgabe:

Modified 
    2 4 6 8 10 12 14 16 18 20 
Original 
    1 2 3 4 5 6 7 8 9 10 
Transformed 
    3 6 9 12 15 18 21 24 27 30 
+0

Nun, ich denke, das ist die beste Antwort, die ich bis jetzt hatte, die keine temporäre Variable oder etwas ähnliches verwendet hat. Danke für den Ansatz. – ash12

0

(Ich bin nicht sicher, warum Ryan freiwillig nicht seine eigene Antwort zu geben, aber ich stimme zu, dass die folgenden sollte funktionieren :)

#include <stdlib.h> // In header 
#include <string.h> 

int Foo(size_t size, int arr[]) 
{ 
    // guard against bad arguments 
    if (arr == NULL || size <= 0) 
    { 
     return -1; 
    } 

    // create local array, since size is variable, allocate dynamically 
    int* arr_2 = NULL; 
    if ((arr_2 = malloc(n * sizeof(*arr_2)) == NULL) 
    { 
     return -1; // malloc allocation error 
    } 
    // otherwise if the size is constant: 
    // int arr_2[SOME_CONSTANT_SIZE]; 

    // copy from arr to arr_2 
    memcpy(arr_2, arr, n * sizeof(*arr_2)); 

    // some computation 

    free(arr_2); 

    return 0; 
} 

Denken Sie daran, dass arr_2 nicht mehr existieren wird, wenn wir den Umfang verlassen von Foo. Außerdem müssen Sie für nicht-primitive Array-Elemente mehr Kopierarbeit leisten.

+0

Tacky, um in dieselbe Zeile zurückzukehren (Inkonsistenz, die meisten Code-Shops werden es nicht zulassen). Whitespace um Betreiber. Überprüfen Sie explizit malloc() gegen NULL anstelle von '!'. Der NOT-Operator funktioniert technisch (weil wir über 0/nicht Null wissen), aber die * Implikation * ist es, einen * booleschen * Wert zu überprüfen, aber Sie suchen wirklich nach einem NULL-Zeiger. Besser Code konsequent schreiben und alles so weit wie möglich klarstellen lassen. Und idiosynkratische Formatierung führt nur zum Turm von Babylon. Jeder hat eine Eigenart. Finden Sie einen soliden C-Stil-Standard und bleiben Sie dabei. Besser auf lange Sicht – clearlight

+0

Vermissen Sie auch ein Komma zwischen Funktionsarg? Eine andere Sache über sehr ordentlich konsistenten Stil ist es viel einfacher und schneller, um Fehler zu fangen. – clearlight

+1

@clearlight Für die Zwecke dieses Beispiels werde ich ändern, was ich habe, aber ist es Ihnen eingefallen, dass ich konsequent One-Liner Argument Guard Return Aussagen (und nur für diesen Zweck?) Ich weiß nicht, ob Sie de betrachten -Referenzierung als etwas, das Leerzeichen benötigt, aber ich denke, es wäre schwerer zu lesen, wenn ich * ptr anstelle von * ptr schreiben würde. – synchronizer

5

Im Allgemeinen können Sie nicht.

Der Anrufer kann so etwas tun;

int main() 
{ 
    int abc[]={5,1,2,9}; 

    { 
     int temp[sizeof (abc)/sizeof (*abc)]; 
     memcpy(temp, abc, sizeof(abc)); 
     Foo(temp); 
    } 
} 

Beachten Sie, dass Foo() keine Informationen über die Anzahl der Elemente in dem Array übergeben erhält.

Wenn Sie wollen Foo() eine ähnliche Sache zu tun, so muss der Anrufer nicht, ist es notwendig, die Anzahl der Elemente als separates Argument übergeben.

void Foo(int arr[], size_t size) /* C99 or later */ 
{ 
     int temp[size]; // VLA 
     memcpy(temp, arr, size*sizeof(int)); 
     /* whatever */ 
} 

oder (vor C99).

void Foo(int arr[], size_t size) /* Before C99 */ 
{ 
     int *temp = malloc(size * sizeof (int)); 
     memcpy(temp, arr, size*sizeof(int)); 
     /* whatever */ 
     free(temp); 
} 

Um einen Speicherverlust zu vermeiden, ist es notwendig, im zweiten Fall um sicherzustellen, dass die Funktion nicht vor zurückkehrt free(temp) aufrufen.

In beiden obigen Versionen von Foo() kann eine zusätzliche Fehlerprüfung erforderlich sein (z. B. um zu erkennen, ob Nullzeiger oder Nullgrößen übergeben wurden, malloc() erfolgreich ist usw.).

+0

Liebe die C99/Pre-C99 Vorbehalt :-) Lord helfen Sie jedem, der ihre Stack-Arrays malloc muss :-) – clearlight

+2

Es ist nicht mallocing Stack-Arrays - seine dynamisch zuweisenden Speicher, um eine Kopie eines Arrays zu halten. Erlauben Sie mir nicht einmal, dass Implementierungen nicht erforderlich sind, um VLAs von C11 aus zu unterstützen. – Peter

+0

Oh ja, ich sprach hastig, meinte mallocing, weil du keine dynamischen Stack-Arrays hast. – clearlight