2010-10-22 15 views
9

Quando si passa un elemento di un array a una funzione, esso viene considerato come una variabile normale e la funzione chiamata crea una copia dell'argomento effettivo e opera su di esso. Qualsiasi modifica apportata negli argomenti formali non influisce sugli argomenti effettivi.Passaggio di un intero array a una funzione

Ma questo non è il caso quando si passa un intero array. In questo caso (chiamata funzione) ottiene l'accesso agli argomenti effettivi e qualsiasi modifica apportata negli argomenti formali influisce sugli argomenti effettivi. Perché questo succede?

+2

Credo la mia risposta (dettagliata) a questa altra domanda http://stackoverflow.com/questions/3613302/passing-array-of-struc tures-to-function-c/3613350 # 3613350 copre anche questo. Fondamentalmente questa è una differenza tra il problema dell'array e dei puntatori. – kriss

+1

Non puoi usare const se non vuoi modificare il contenuto dell'array? – Nyan

risposta

16

L'array viene passato come puntatore agli elementi.

se scrivo:

void doStuff(int *ptr) 
{ 
    ptr[1] = 5; 
} 

int main() 
{ 
    int arr[] = {0, 1, 2}; 
    doStuff(arr); 
    printf("%d %d %d\n", arr[0], arr[1], arr[2]); 
} 

l'uscita sarà "0 5 2". Questo perché C passa qualunque cosa sia effettivamente il parametro in base al valore. Il parametro è un puntatore a un int. Quindi un puntatore a un int è passato per valore. Pertanto, doStuff ottiene una copia di un puntatore sulla memoria nel frame dello stack principale. Quando si dereferenzia quel puntatore a ptr[1], segue il puntatore alla memoria principale e modifica l'array lì.

C può passare solo per valore, ma lo fa "superficialmente". Se gli chiedi di passare un * int, passerà un * int. Copia solo il valore del puntatore, non i valori di qualsiasi cosa a cui punta.

Se si desidera doStuff per ottenere la propria copia della matrice, sia avvolgere la matrice in una struttura come altri hanno suggerito, o utilizzare memcpy per copiare manualmente in profondità l'array come questo:

void doStuff(int *ptr, int nElems) 
{ 
    int myCopyOfTheArray[nElems]; 
    memcpy(myCopyOfTheArray, ptr, sizeof(int) * nElems); 
    /* do stuff with the local copy */ 
} 

A differenza di una struct, l'approccio memcpy funziona se nElems è conosciuto solo al runtime.

+0

Il secondo snippet di codice, è valido C o solo pseudo C ??? – Nyan

+0

Ok, quale compilatore stai usando? solo curioso. – Nyan

+0

gcc versione 4.1.2 – AlcubierreDrive

0

Una matrice in C può essere considerata come un puntatore al primo elemento dell'array. Il puntatore viene passato per valore (non è possibile modificare il valore passato in), ma è possibile dereferenziarlo e modificare la memoria a cui punta.

+4

Una matrice in C non è un puntatore, spesso è * abbassata a un puntatore. –

+0

@Matteo, @paxdiablo Risolto. – Jonathan

8

Le matrici non possono essere passate per valore in C. Vengono declassate ai puntatori. Quindi la funzione chiamata vede un puntatore all'array (passato per riferimento) e opera su di esso. Se vuoi fare una copia, devi farlo esplicitamente, o mettere la tua matrice all'interno di una struct (che può essere passata per valore alle funzioni.)

0

Perché quando si passa un intero array per funzionare Si passa un puntatore a quell'array, il che significa che si dà alla funzione un posto nella memoria in cui si trova questo array. Quindi, quando si modifica la matrice in funzione, si sta modificando anche la matrice originale.

5

È costoso eseguire una copia di un intero array, in generale. Nei giorni in cui C fu creato per la prima volta, potrebbe facilmente esaurire le risorse della macchina (in particolare lo stack).

Se davvero si vuole passare un array, avvolgerlo in una struttura:

struct wrap { int array[100]; }; 

int somefunc(struct wrap large) { ... } 

void anotherfunc(void) 
{ 
    struct wrap a; 
    ...add data to array... 
    printf("%d\n", somefunc(a)); 
} 
2

"passano di riferimento" è un diversivo in C. Tutti gli argomenti di una funzione vengono "passati per valore" solo . Nel caso degli array, si passa l'indirizzo del primo elemento sotto forma di un puntatore. È quindi possibile utilizzare questo puntatore per fare riferimento alla posizione di memoria desiderata & valori di lettura o scrittura.

2

Dal online C standard:

6.3.2.1 lvalue, array e designatori funzione
...
3 Tranne quando è l'operando della sizeof operatore o l'unario & operatore, oppure è una stringa letterale utilizzato per inizializzare un array, un'espressione che ha tipo "array di tipo" viene convertito in un'espressione con tipo "puntatore a tipo" che punta all'elemento iniziale dell'oggetto array e non è un lvalue. Se l'oggetto array ha una classe di archiviazione di registro, il comportamento non è definito.

assumere il seguente frammento di codice:

int a[10]; 
... 
foo(a); 

Nella chiamata al foo, il tipo di espressionea è "10-elemento array di int". Tuttavia, poiché l'espressione non è l'operando degli operatori sizeof o & e poiché non è una stringa letterale utilizzata per inizializzare un'altra matrice in una dichiarazione, il suo tipo viene convertito implicitamente ("decadimenti") da "10- array di elementi di int "a" puntatore a int "e il suo valore sarà l'indirizzo del primo elemento nell'array (ad esempio &a[0]).

Pertanto, ciò che foo riceve è un puntatore a int, non un array. Dereferenziare o sottoscrivere questo puntatore consente di modificare i valori dell'array.

Questa è una funzionalità del linguaggio C; gli array non sono oggetti di prima classe. In effetti, nella maggior parte dei casi (incluso l'indice) le espressioni dell'array verranno convertite in tipi di puntatore.

continuo sottolineando la parola espressione distinguere tra il campo attuale oggetto (che è sempre e comunque un tipo array) e ogni riferimento a tale oggetto nel codice, che può essere convertito in un puntatore genere.

3

Non ho ancora visto nessuna risposta per l'intera domanda. Da quello che vedo, sembra che la domanda chiede qualcosa di simile:

Dato il seguente codice:

int a[5]; 

foo(a); 
bar(a[0]); 

Perché può foo manipolare i valori originali mentre bar riceve solo una copia del valore di essere passato in ?

Questo a causa dell'uso della notazione di matrice: l'operatore [] dereferenzia l'elemento a cui fa riferimento nell'array e passa il valore in quella posizione.

Così

int a[5]; 
bar(a[0]); 

è diverso:

int* a; 
bar(a); 

Se si desidera passare a un riferimento a una specifica voce di un array, è necessario utilizzare il & dell'operatore:

bar(&a[5]); 
Problemi correlati