2016-06-14 42 views
9

Perché questo pezzo di codice:Anello non riconosciuto per loop?

void printarray(int array[]) { 
    for (int x: array) { 
     std::cout << x << std::endl; 
    } 
} 

generare questo errore di compilazione?

error: 'begin' was not declared in this scope 
    for (int x: array) { 

Cosa ottengo sbagliato gamma basata for loop?

+6

In questo contesto 'int array []' realtà non è un array, ma equivalente a 'int * array'. All'interno della funzione non conosciamo la dimensione del parametro. Vedi [Sizeof a array in the C programming language] (http://stackoverflow.com/questions/1975128/sizeof-an-array-in-the-c-programming-language) –

+0

usa il modo più semplice: void printarray (std :: vector array) {... –

+0

@Bo Persson Potrebbe inlining la funzione help? – user6245072

risposta

5

Quando una matrice viene passata per valore come argomento di una funzione, viene implicitamente convertita in puntatore al suo primo elemento. Anche i parametri che dichiarano gli array sono adattati ai puntatori.

Così, per esempio, queste le dichiarazioni di funzioni

void printarray(int array[100]); 
void printarray(int array[10]); 
void printarray(int array[]); 

dichiara la stessa funzione ed equivalente a

void printarray(int *array); 

Quindi è necessario passare anche la dimensione della matrice alla funzione come per esempio

void printarray(const int array[]. size_t n) 
{ 
    for (size_t i = 0; i < n; i++) 
    { 
     std::cout << a[i] << std::endl; 
    } 
} 

È possibile scrivere una funzione modello appositamente per gli array p assed per riferimento come ad esempio

template <size_t N> 
void printarray(const int (&array)[N]) 
{ 
    for (int x : array) 
    { 
     std::cout << x << std::endl; 
    } 
} 

o

template <typename T, size_t N> 
void printarray(const T (&array)[N]) 
{ 
    for (auto x : array) 
    { 
     std::cout << x << std::endl; 
    } 
} 

Tuttavia rispetto alla funzione precedente ha un inconveniente perché gli array di dimensioni diverse sono diversi tipi e il compilatore genererà altrettante funzioni del modello come molti array di diversi tipi che userete con la funzione.

E è possibile utilizzare algoritmi standard come ad esempio std::copy o std::for_each per generare un array.

Ad esempio

#include <iostream> 
#include <algorithm> 
#include <iterator> 

int main() 
{ 
    int array[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 

    std::copy(std::begin(array), std::end(array), 
       std::ostream_iterator<int>(std::cout, "\n")); 

    return 0; 
} 

Un altro approccio è quello di utilizzare standard classe std::array che ha funzioni membro appropriati begin e end che vengono utilizzati dal l'intervallo basato for. Per esempio

#include <iostream> 
#include <array> 

const size_t N = 10; 

void printarray(const std::array<int, N> &array) 
{ 
    for (int x : array) std::cout << x << std::endl; 
} 

int main() 
{ 
    std::array<int, N> array = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 

    printarray(array); 

    return 0; 
} 

Ma in questo caso è necessario anche scrivere una funzione di modello se avete intenzione di oggetti di uscita della classe std::array con i numeri o tipi di elementi diversi.

Ad esempio

#include <iostream> 
#include <array> 

template <typename T, size_t N> 
void printarray(const std::array<T, N> &array) 
{ 
    for (auto x : array) std::cout << x << std::endl; 
} 

int main() 
{ 
    std::array<int, 10> array1 = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 

    printarray(array1); 

    std::array<char, 10> array2 = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J' }; 

    printarray(array2); 

    return 0; 
} 
1

Il parametro printarray riceve è in realtà un * int, l'intervallo per non sapere dove fermarsi. In questo caso è necessario inviare la lunghezza come parametro e fare una regolare per

13

Il tuo problema è che array non è in realtà un array. Quando si scrive

void printarray(int array[]) 

E 'lo stesso di

void printarray(int* array) 

Dal momento che non si può dire quanti elementi puntatore viene senza un parametro aggiuntivo dimensione non è possibile utilizzarlo con una variava based per ciclo.

Quello che devi fare è passare l'array per riferimento in modo che gli array non decadano in un puntatore. Se si conosce l'esatta dimensione della matrice, è possibile utilizzare

void printarray(int (&array)[size_you_want_here]) 

Se si vuole rendere la funzione più generica in modo che possa lavorare con diversi array di dimensioni quindi è possibile utilizzare un modello come

template<std::size_t N> 
void printarray(int (&array)[N]) 

In entrambi i casi sopra riportati ora hai un array effettivo invece di un puntatore, quindi puoi usarlo con un ciclo basato su intervalli.

noti inoltre siamo in grado di rendere la funzione del tutto generico utilizzando

template<typename T, std::size_t N> 
void printarray(T (&array)[N]) { 
    for (auto&& x : array) { 
     std::cout << x << "\n"; 
    } 
} 

Noterete anche a cambiare std::endl a "\n". Normalmente non si desidera utilizzare endl poiché chiama esplicitamente lo flush() nello stream. Generalmente lo "\n" è tutto ciò di cui hai bisogno e alla fine se l'output non è ancora scaricato, puoi chiamare tu stesso lo flush().

+0

Perché 'auto && x' però? – user6245072

+0

@ user6245072 È solo per abitudine. Puoi anche usare 'const auto &' per renderlo di sola lettura e riferimento. – NathanOliver