Hai già alcune risposte per C e una risposta per C++, ma c'è un altro modo per farlo in C++.
Come detto Nawaz, per passare una matrice di dimensione N, è possibile farlo in C++:
const size_t N = 16; // For your question.
void foo(int (&arr)[N]) {
// Do something with arr.
}
Tuttavia, come di C++ 11, è anche possibile utilizzare std :: contenitore array, che può essere passato con una sintassi più naturale (assumendo una certa familiarità con la sintassi del template).
#include <array>
const size_t N = 16;
void bar(std::array<int, N> arr) {
// Do something with arr.
}
Come contenitore, std :: matrice permette principalmente la stessa funzionalità di una normale matrice stile C, mentre anche l'aggiunta funzionalità aggiuntive.
std::array<int, 5> arr1 = { 1, 2, 3, 4, 5 };
int arr2[5] = { 1, 2, 3, 4, 5 };
// Operator[]:
for (int i = 0; i < 5; i++) {
assert(arr1[i] == arr2[i]);
}
// Fill:
arr1.fill(0);
for (int i = 0; i < 5; i++) {
arr2[i] = 0;
}
// Check size:
size_t arr1Size = arr1.size();
size_t arr2Size = sizeof(arr2)/sizeof(arr2[0]);
// Foreach (C++11 syntax):
for (int &i : arr1) {
// Use i.
}
for (int &i : arr2) {
// Use i.
}
Tuttavia, a mia conoscenza (che è certamente limitata al momento), l'aritmetica dei puntatori non è al sicuro con std :: array di meno di utilizzare i dati funzione membro() per ottenere l'indirizzo della matrice reale prima. Questo è sia per prevenire future modifiche alla classe std :: array dalla rottura del codice, sia perché alcune implementazioni STL possono memorizzare ulteriori dati oltre alla matrice effettiva.
Si noti che questo sarebbe più utile per il nuovo codice, o se si converte il codice pre-esistente da utilizzare std :: array invece di array in stile C. Dato che std :: array sono tipi aggregati, mancano costruttori personalizzati e quindi non è possibile passare direttamente dall'array in stile C a std :: array (a meno di usare un cast, ma è brutto e può potenzialmente causare problemi in futuro).Per convertirli, si avrebbe invece bisogno di usare qualcosa di simile:
#include <array>
#include <algorithm>
const size_t N = 16;
std::array<int, N> cArrayConverter(int (&arr)[N]) {
std::array<int, N> ret;
std::copy(std::begin(arr), std::end(arr), std::begin(ret));
return ret;
}
Pertanto, se il codice utilizza le matrici in stile C e sarebbe fattibile per convertirlo per usare std :: array, invece, si sarebbe meglio attenersi agli array in stile C.
(Nota: ho specificato dimensioni come N in modo da poter più facilmente riutilizzare il codice ovunque ne abbiate bisogno.)
Edit: Ci sono alcune cose che ho dimenticato di menzionare:
1) La maggior parte delle funzioni di libreria standard C++ progettate per operare su container sono indipendenti dall'implementazione; invece di essere progettati per contenitori specifici, operano su intervalli, utilizzando iteratori. (Questo significa anche che lavorano per std::basic_string
e istanze della stessa, come ad esempio std::string
.) Ad esempio, std::copy
ha il seguente prototipo:
template <class InputIterator, class OutputIterator>
OutputIterator copy(InputIterator first, InputIterator last,
OutputIterator result);
// first is the beginning of the first range.
// last is the end of the first range.
// result is the beginning of the second range.
Anche se questo può sembrare imponente, in genere non è necessario specificare il modello parametri, e può semplicemente lasciare che il compilatore gestisca quello per te.
std::array<int, 5> arr1 = { 1, 2, 3, 4, 5 };
std::array<int, 5> arr2 = { 6, 7, 8, 9, 0 };
std::string str1 = ".dlrow ,olleH";
std::string str2 = "Overwrite me!";
std::copy(arr1.begin(), arr1.end(), arr2.begin());
// arr2 now stores { 1, 2, 3, 4, 5 }.
std::copy(str1.begin(), str1.end(), str2.begin());
// str2 now stores ".dlrow ,olleH".
// Not really necessary for full string copying, due to std::string.operator=(), but possible nonetheless.
causa basandosi su iteratori, queste funzioni sono anche compatibili con array C-stile (come iteratori sono una generalizzazione di puntatori, tutti i puntatori sono per definizione iteratori (ma non tutti iteratori sono necessariamente puntatori)). Questo può essere utile quando si lavora con codice legacy, poiché significa che si ha pieno accesso alle funzioni di intervallo nella libreria standard.
int arr1[5] = { 4, 3, 2, 1, 0 };
std::array<int, 5> arr2;
std::copy(std::begin(arr1), std::end(arr1), std::begin(arr2));
Avrete notato da questo esempio e l'ultima che std::array.begin()
e std::begin()
possono essere usati in modo intercambiabile con std::array
. Questo perché std::begin()
e std::end()
sono implementati in modo tale che per qualsiasi contenitore, hanno lo stesso tipo di ritorno e restituiscono lo stesso valore, come chiamando le funzioni membro begin()
e end()
di un'istanza di quel contenitore.
// Prototype:
template <class Container>
auto begin (Container& cont) -> decltype (cont.begin());
// Examples:
std::array<int, 5> arr;
std::vector<char> vec;
std::begin(arr) == arr.begin();
std::end(arr) == arr.end();
std::begin(vec) == vec.begin();
std::end(vec) == vec.end();
// And so on...
array C-stile non hanno funzioni membro, che richiede l'uso di std::begin()
e std::end()
per loro. In questo caso, le due funzioni sono sovraccariche per fornire i puntatori applicabili, in base al tipo di matrice.
// Prototype:
template <class T, size_t N>
T* begin (T(&arr)[N]);
// Examples:
int arr[5];
std::begin(arr) == &arr[0];
std::end(arr) == &arr[4];
Come regola generale, se non siete sicuri circa o meno qualsiasi segmento particolare codice dovrà utilizzare le matrici in stile C, è più sicuro da usare std::begin()
e std::end()
.
[Si noti che mentre si utilizzava std::copy()
come esempio, l'uso di intervalli ed iteratori è molto comune nella libreria standard. La maggior parte, se non tutte, le funzioni progettate per operare su container (o più specificamente, qualsiasi implementazione di Container concept, come std::array
, std::vector
e std::string
) utilizzano intervalli, rendendoli compatibili con qualsiasi contenitore attuale e futuro, nonché con C matrici in stile. Potrebbero esserci delle eccezioni a questa diffusa compatibilità di cui non sono a conoscenza.]
2) Quando si passa uno std :: array per valore, è possibile che si verifichi un notevole sovraccarico, a seconda della dimensione dell'array.Di conseguenza, di solito è meglio passarlo per riferimento o utilizzare iteratori (come la libreria standard).
// Pass by reference.
const size_t N = 16;
void foo(std::array<int, N>& arr);
3) Tutti questi esempi presuppongono che tutte le matrici nel codice saranno uguali dimensioni, come specificato dalla costante N
. Per rendere il tuo codice più indipendente dall'implementazione, puoi utilizzare gli intervalli & iteratori oppure, se desideri mantenere il codice focalizzato sugli array, utilizzare le funzioni basate su modelli. [Sulla this answer to another question.]
template<size_t SZ> void foo(std::array<int, SZ>& arr);
...
std::array<int, 5> arr1;
std::array<int, 10> arr2;
foo(arr1); // Calls foo<5>(arr1).
foo(arr2); // Calls foo<10>(arr2).
Se facendo questo, si può anche andare fino al punto di modello di tipo di nonché membro dell'array, a condizione che il codice può operare su tipi diversi int.
template<typename T, size_t SZ>
void foo(std::array<T, SZ>& arr);
...
std::array<int, 5> arr1;
std::array<float, 7> arr2;
foo(arr1); // Calls foo<int, 5>(arr1).
foo(arr2); // Calls foo<float, 7>(arr2).
Per un esempio di questo in azione, vedere here.
Se qualcuno vede degli errori che potrei aver perso, sentitevi liberi di indicarli per me di correggerli o di correggerli voi stessi. Penso di averli presi tutti, ma non ne sono sicuro al 100%.
In realtà impedirebbe all'utente di eseguire un array [17] o array [15]? quando penso a cosa sia esattamente int [], sullo sfondo è un puntatore int ad un array non dinamico. Quindi il programma/il compilatore rifiuterebbe automaticamente una lunghezza diversa, o lo accetterebbe e cercherebbe di gestirlo nel miglior modo possibile? –
Questo è esattamente giusto, ho cancellato la mia risposta dopo il test. Ho pensato che avrei potuto diventare complicato con un altro uso per static (AUFS) e andare con 'void foo di C99 (int a [statico 16]);' ma ho appena realizzato che garantisce * almeno * 16 membri non * esattamente * come voluto da l'OP – SiegeX
Quindi, se passo un array che non è di dimensione 16, non verrà compilato? diciamo che ho int intray [20]; special_case (e intArray). Questo verrà compilato? – armanali