Apparentemente, possiamo passare istanze di classi complesse a funzioni, ma perché non possiamo passare gli array alle funzioni?
L’origine è storica. Il problema è che la regola “decadimento degli array in puntatori, quando passata a una funzione” è semplice.
Copiare gli array sarebbe un po ‘complicato e non molto chiaro, poiché il comportamento cambierebbe per diversi parametri e dichiarazioni di funzioni diverse.
Tieni presente che puoi ancora eseguire un passaggio indiretto per valore:
struct A { int arr[2]; }; void func(struct A);
Ecco un’altra prospettiva: non c’è un singolo tipo “array” in C. Piuttosto, T[N]
è un tipo diverso per ogni N
Quindi T[1]
, T[2]
, ecc. Sono tutti tipi diversi .
In C non c’è sovraccarico di funzioni, e quindi l’unica cosa sensata che avresti potuto permettere sarebbe una funzione che prende (o restituisce) un singolo tipo di array :
void foo(int a[3]); // hypothetical
Presumibilmente, ciò è stato considerato molto meno utile della decisione effettiva di trasformare tutti gli array in un puntatore al primo elemento e richiedere all’utente di comunicare le dimensioni con altri mezzi. Dopotutto, quanto sopra potrebbe essere riscritto come:
void foo(int * a) { static const unsigned int N = 3; /* ... */ }
Quindi non c’è perdita di potere espressivo, ma un enorme guadagno di generalità.
Nota che questo non è diverso in C ++, ma la generazione di codice basata su template ti permette di scrivere una funzione basata su template foo(T (&a)[N])
, dove N
è dedotto per te – ma questo significa solo che puoi creare un’intera famiglia di funzioni distinte e diverse , una per ogni valore di N
Come caso estremo, immagina che avresti bisogno di due funzioni print6(const char[6])
e print12(const char[12])
per dire print6("Hello")
e print12("Hello World")
se non lo facessi vuoi decadere gli array ai puntatori o altrimenti dovresti aggiungere una conversione esplicita, print_p((const char*)"Hello World")
.
Rispondendo a una domanda molto vecchia, dato che Question è market con C ++ che si aggiunge solo a fini di completamento, possiamo usare std :: array e passa array a funzioni per valore o per riferimento che fornisce protezione contro l’accesso agli indici fuori limite:
qui sotto è il campione:
#include #include //pass array by reference template void fill_array(std::array& arr){ for(int idx = 0; idx < arr.size(); ++idx) arr[idx] = idx*idx; } //pass array by value template void print_array(std::array arr){ for(int idx = 0; idx < arr.size(); ++idx) std::cout << arr[idx] << std::endl; } int main() { std::array arr; fill_array(arr); print_array(arr); //use different size std::array arr2; fill_array(arr2); print_array(arr2); }
Il motivo per cui non è ansible passare un array in base al valore è perché non esiste un modo specifico per tenere traccia delle dimensioni di un array in modo tale che la logica di chiamata di funzione possa sapere quanta memoria allocare e cosa copiare. È ansible passare un’istanza di class perché le classi hanno costruttori. Gli array no
Stai passando per valore: il valore del puntatore all’array. Ricorda che usare la notazione delle parentesi quadre in C è semplicemente una scorciatoia per de-referenziare un puntatore. ptr [2] significa * (ptr + 2).
Lasciando cadere le parentesi si ottiene un puntatore all’array, che può essere passato per valore a una funzione:
int x[2] = {1, 2}; int result; result = DoSomething(x);
Vedere l’ elenco dei tipi nelle specifiche ANSI C. Gli array non sono tipi primitivi, ma costruiti da una combinazione di puntatori e operatori. (Non mi consente di inserire un altro link, ma la costruzione è descritta sotto “Derivazione del tipo di matrice”.)
&a = a = &(a[0])
void by_value(bool* arr) // pointer_value passed by value { arr[1] = true; arr = NULL; // temporary pointer that points to original array } int main() { bool a[3] = {}; cout << a[1] << endl; // 0 by_value(a); cout << a[1] << endl; // 1 !!! }
indirizzi:
[main] a = 0046FB18 // **Original** &a = 0046FB18 // **Original** [func] arr = 0046FB18 // **Original** &arr = 0046FA44 // TempPTR [func] arr = NULL &arr = 0046FA44 // TempPTR
void by_value(bool* arr) { cout << &arr << arr; // &arr != arr } int main() { bool a[3] = {}; cout << &a << a; // &a == a == &a[0] by_value(arr); }
indirizzi
Prints: [main] 0046FB18 = 0046FB18 [func] 0046FA44 != 0046FB18
Notare che:
leggi di più:
rvalue
Array Decay
L’equivalente sarebbe quello di fare prima una copia dell’array e poi passarlo alla funzione (che può essere molto inefficiente per i grandi array).
Oltre a questo, direi che è per ragioni storiche, vale a dire che non è ansible passare gli array in base al valore in C.
La mia ipotesi è che il ragionamento alla base del fatto che NON introducendo matrici di valore in C ++ fosse che gli oggetti erano moderatamente dimensionati rispetto agli array.
Come sottolineato da delnan, quando si usa std::vector
si possono effettivamente passare oggetti di tipo array a funzioni per valore.
in realtà, un puntatore all’array viene passato per valore , usando quel puntatore all’interno della funzione chiamata si avrà la sensazione che l’array sia passato per riferimento che è sbagliato. prova a cambiare il valore nel puntatore dell’array in modo che punti ad un altro array nella tua funzione e scoprirai che l’array originale non è stato influenzato, il che significa che l’array non viene passato per riferimento.