2016-06-14 189 views
9

爲什麼這段代碼:無法識別的基於範圍的循環?

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

生成此編譯時錯誤?

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

我對基於範圍的for循環有什麼問題?

+6

在這方面'int數組[]'確實不是數組,但相當於'INT * array'。在函數內部,我們不知道參數的大小。請參閱[在C編程語言中使用數組的大小](http://stackoverflow.com/questions/1975128/sizeof-an-array-in-the-c-programming-language) –

+0

使用最簡單的方法:void printarray(std :: vector array){... –

+0

@Bo Persson是否可以嵌入函數幫助? – user6245072

回答

5

當一個數組作爲函數的參數傳遞時,它會隱式轉換爲指向其第一個元素的指針。聲明數組的參數也被調整爲指針。

因此,例如,這些函數聲明

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

聲明的同一個功能,相當於

void printarray(int *array); 

所以你還需要數組的大小傳遞給函數,例如

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

你可以寫一個專門用於數組p的模板函數通過引用稱職如例如

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

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

但是與先前的函數它有一個缺點,因爲不同大小的陣列是不同類型和編譯器會生成從模板儘可能多的功能相比儘可能多的不同類型的數組將用於該函數。

而且您可以使用標準算法,例如std::copystd::for_each來輸出數組。

例如

#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; 
} 

另一種方法是使用標準的類std::array,其具有通過基於for語句的範圍使用合適的成員函數beginend。例如

#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; 
} 

但在這種情況下,你也需要寫一個模板函數,如果你要使用不同數量或類型的元素std::array類的輸出對象。

例如

#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

printarray接收的參數實際上是一個int *,範圍不知道從哪裏停止。在這種情況下,您將需要發送長度作爲參數,並執行常規操作。

13

您的問題是array實際上不是數組。當你寫

void printarray(int array[]) 

這是一樣的

void printarray(int* array) 

既然你不能告訴多少個元素的指針指向而無需額外的大小參數,則不能使用遠程基於for循環使用。

你需要做的是通過引用傳遞數組,以便數組不會衰變成指針。如果你知道數組的確切大小,那麼你可以使用

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

如果你想使功能更加通用的,因此它可以與不同大小的數組工作,那麼你可以使用一個模板像

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

我上述兩種情況下,你現在有一個實際的數組而不是一個指針,所以你可以使用它與基於範圍的for循環。

另外請注意,我們可以使用

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

使功能完全通用的,您還會注意到我改變std::endl"\n"。通常,您不希望使用endl,因爲它明確地在流上調用flush()。一般"\n"是你所需要的,最後如果輸出還沒有被刷新,那麼你可以自己撥打flush()

+0

爲什麼'auto && x'雖然? – user6245072

+0

@ user6245072這只是出於習慣。你也可以使用'const auto&'使它成爲只讀和引用。 – NathanOliver