2009-08-25 15 views
57

Với chương trình sau đây,Khi một hàm có tham số mảng kích thước cụ thể, tại sao nó được thay thế bằng một con trỏ?

#include <iostream> 

using namespace std; 

void foo(char a[100]) 
{ 
    cout << "foo() " << sizeof(a) << endl; 
} 

int main() 
{ 
    char bar[100] = { 0 }; 
    cout << "main() " << sizeof(bar) << endl; 
    foo(bar); 
    return 0; 
} 

đầu ra

main() 100 
foo() 4 
  1. Tại sao mảng thông qua như là một con trỏ đến phần tử đầu tiên?
  2. Đây có phải là di sản từ C?
  3. Tiêu chuẩn nói gì?
  4. Tại sao mức độ an toàn nghiêm ngặt của C++ giảm?
+0

tôi luôn luôn sử dụng std :: mảng trong những trường hợp này, ngăn chặn việc phải đối phó với các vấn đề như thế này và làm việc với các thuật toán std quá – paulm

+2

gì nghiêm ngặt loại an toàn? Ai đã hứa an toàn loại nghiêm ngặt? Không có điều như vậy trong C++. –

+0

TL; DR cho câu trả lời dưới đây: Mảng trở thành con trỏ khi được chuyển đến hàm, vì vậy khi bạn kiểm tra kích thước của chúng, tất cả những gì bạn nhận được là kích thước của con trỏ. Nếu bạn đang làm việc với chỉ C, tất cả những gì tôi có thể đề nghị là bạn tính trước bất kỳ kích thước nào bạn đang cố gắng thoát khỏi mảng như một tham số khác. –

Trả lời

63

Có nó thừa hưởng từ C. Chức năng:

void foo (char a[100]); 

sẽ có các tham số điều chỉnh để có một con trỏ, và do đó trở thành:

void foo (char * a); 

Nếu bạn muốn loại mảng được giữ nguyên, bạn nên chuyển tham chiếu đến mảng:

void foo (char (&a)[100]); 

C++ '03 8.3.5/3:

... Các loại một chức năng được xác định bằng cách sử dụng quy tắc sau đây. Kiểu của mỗi tham số được xác định từ trình khai báo-khai báo-seq và khai báo của chính nó. Sau khi xác định loại của mỗi thông số, bất kỳ tham số nào của loại "mảng T" hoặc "hàm trả về T" được điều chỉnh thành "con trỏ tới T" hoặc "con trỏ đến hàm T trả về T", tương ứng ....

Để giải thích cú pháp:

Kiểm tra quy tắc "bên trái" trong google; Tôi đã tìm thấy một mô tả về nó here.

Nó sẽ được áp dụng cho ví dụ này xấp xỉ như sau:

void foo (char (&a)[100]); 

Bắt đầu ở dạng 'a'

'a' là một

Move đúng - chúng ta thấy a ) vì vậy chúng tôi đảo ngược hướng tìm kiếm (. Như chúng ta đã di chuyển trái chúng tôi vượt qua &

'a' là một tài liệu tham khảo

Sau & chúng ta đạt đến việc mở ( vì vậy chúng tôi đảo ngược một lần nữa và nhìn bên phải. Bây giờ chúng ta thấy [100]

'a' là một tham chiếu đến một mảng của 100

Và chúng ta đảo ngược hướng một lần nữa cho đến khi chúng ta đạt char:

'a' là một tham chiếu đến một mảng 100 ký tự

+1

Sau này có nhược điểm của việc kích cỡ mảng cứng vào chữ ký hàm. Một mẫu chức năng có thể tránh được điều đó. – sbi

+0

Trên một lưu ý hơi liên quan, ai đó có thể làm rõ cú pháp của các bên trên cho tôi? Tôi rõ ràng là thiếu một cái gì đó, nhưng tôi không hoàn toàn thấy làm thế nào mà đánh giá để tham chiếu đến một mảng; nó trông giống như một mảng tài liệu tham khảo. – suszterpatt

+4

nó có thể đáng nói đến việc sử dụng một std :: vector sẽ gọn gàng bên bước tất cả các vấn đề liên quan đến mảng đi qua. – markh44

12

Có. Trong C và C++ bạn không thể truyền mảng vào hàm. Nó là như vậy.

Tại sao bạn vẫn làm mảng đồng bằng? Bạn đã xem số boost/std::tr1::array/std::array hoặc std::vector?

Lưu ý rằng bạn có thể chuyển một tham chiếu đến một mảng có độ dài tùy ý đến hàm mẫu. Off đỉnh đầu của tôi:

template< std::size_t N > 
void f(char (&arr)[N]) 
{ 
    std::cout << sizeof(arr) << '\n'; 
} 
+5

Nhưng bạn có thể chuyển vào "tham chiếu đến mảng". –

+0

Chỉ một số mã di sản – CsTamas

+0

@Richard: Tôi vừa thêm nội dung này vào khi bạn viết nhận xét của mình. ':)' – sbi

1

Có một từ tuyệt vời trong thuật ngữ C/C++ được sử dụng cho mảng tĩnh d con trỏ hàm - phân rã. Xét đoạn mã sau:

int intArray[] = {1, 3, 5, 7, 11}; // static array of 5 ints 
//... 
void f(int a[]) { 
    // ... 
} 
// ... 
f(intArray); // only pointer to the first array element is passed 
int length = sizeof intArray/sizeof(int); // calculate intArray elements quantity (equals 5) 
int ptrToIntSize = sizeof(*intArray); // calculate int * size on your system 
+1

Và? Điều này, tốt nhất, gián tiếp chỉ ra _what_ xảy ra. OP đã yêu cầu _why_ ngôn ngữ được thiết lập theo cách đó. Ngoài ra, "mảng tĩnh" là một thuật ngữ khó hiểu khi những gì bạn thực sự có nghĩa là được phân bổ động; về mặt kỹ thuật, mảng bạn đã hiển thị có liên kết 'extern', không phải' tĩnh'. Và tôi không chắc chắn những gì con trỏ chức năng phải làm gì với bất cứ điều gì ở đây? –

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