2016-06-14 17 views
9

Tại sao đoạn mã này:Không được công nhận dựa trên phạm vi cho vòng lặp?

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

Tạo lỗi biên dịch này?

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

Tôi nhận được gì sai về phạm vi dựa trên phạm vi for vòng?

+6

Trong bối cảnh này 'int array []' thực sự không phải là một mảng, nhưng tương đương với 'int * array'. Bên trong hàm chúng ta không biết kích thước của tham số. Xem [Sizeof một mảng trong ngôn ngữ lập trình C] (http://stackoverflow.com/questions/1975128/sizeof-an-array-in-the-c-programming-language) –

+0

sử dụng cách dễ nhất: void printarray (std :: vector mảng) {... –

+0

@Bo Persson Có thể gạch chân chức năng trợ giúp không? – user6245072

Trả lời

5

Khi một mảng được truyền theo giá trị làm đối số của một hàm, nó được chuyển thành con trỏ đến phần tử đầu tiên của nó. Ngoài ra các tham số khai báo mảng được điều chỉnh cho con trỏ.

Vì vậy, ví dụ như những tờ khai chức năng

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

tuyên bố cùng một chức năng và tương đương với

void printarray(int *array); 

Vì vậy, bạn cần phải vượt qua cũng là kích thước của mảng đến chức năng như ví dụ

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

Bạn có thể viết chức năng mẫu đặc biệt cho mảng p assed bằng cách tham chiếu như ví dụ

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

hoặc

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

Tuy nhiên so với các chức năng trước đây nó có một nhược điểm vì mảng của các kích cỡ khác nhau là khác nhau và trình biên dịch sẽ tạo ra càng nhiều chức năng từ mẫu như nhiều mảng của các loại khác nhau mà bạn sẽ sử dụng với hàm.

Và bạn có thể sử dụng các thuật toán chuẩn như ví dụ std::copy hoặc std::for_each để xuất một mảng.

Ví dụ

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

phương pháp khác là sử dụng tiêu chuẩn lớp std::array có chức năng thành viên thích hợp beginend được sử dụng bởi phạm vi dựa cho tuyên bố. Ví dụ

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

Nhưng trong trường hợp này, bạn cũng cần phải viết một hàm template nếu bạn đang đi để đối tượng đầu ra của lớp std::array với những con số hoặc các loại của các yếu tố khác nhau.

Ví dụ

#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

Tham số printarray nhận được thực sự là int *, phạm vi không biết dừng ở đâu. Trong trường hợp này, bạn cần phải gửi độ dài làm thông số và thực hiện thường xuyên cho

13

Vấn đề của bạn là array không thực sự là một mảng. Khi bạn viết

void printarray(int array[]) 

Nó cũng giống như

void printarray(int* array) 

Vì bạn không thể biết bao nhiêu yếu tố một con trỏ trỏ đến mà không có một thông số kích thước bổ sung mà bạn không thể sử dụng nó với một tầm xa dựa vòng lặp for.

Điều bạn cần làm là chuyển mảng theo tham chiếu sao cho các mảng không phân rã thành con trỏ. Nếu bạn biết kích thước chính xác của mảng sau đó bạn có thể sử dụng

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

Nếu bạn muốn chắc một hàm tổng quát hơn để nó có thể làm việc với mảng kích thước khác nhau thì bạn có thể sử dụng một mẫu như

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

Tôi cả hai trường hợp trên bây giờ bạn có một mảng thực tế thay vì một con trỏ để bạn có thể sử dụng nó với một phạm vi dựa trên vòng lặp.

Cũng lưu ý chúng ta có thể thực hiện các chức năng hoàn toàn generic sử dụng

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

Bạn cũng sẽ thấy tôi thay đổi std::endl để "\n". Thông thường, bạn không muốn sử dụng endl vì nó gọi rõ ràng flush() trên luồng. Nói chung, "\n" là tất cả những gì bạn cần và cuối cùng nếu đầu ra vẫn chưa được xả thì bạn có thể tự gọi số flush().

+0

Tại sao 'auto && x'? – user6245072

+0

@ user6245072 Đó chỉ là thói quen. Bạn cũng có thể sử dụng 'const auto &' để làm cho nó chỉ đọc và tham chiếu. – NathanOliver

Các vấn đề liên quan