2009-06-20 45 views
11

Tôi đã đọc cuốn sách của K & R trên C và thấy rằng số học con trỏ trong C cho phép truy cập vào một phần tử ngoài phần cuối của mảng. Tôi biết C cho phép làm hầu như bất cứ điều gì với bộ nhớ nhưng tôi chỉ không hiểu, mục đích của đặc thù này là gì?C - phần tử nằm ngoài phần đầu của một mảng

+1

Xem thêm câu hỏi này: http://stackoverflow.com/questions/988158/take-the-address-of-a-one-past-the-end-array-element-via-subscript-legal-by- các –

Trả lời

19

C không cho phép truy cập vào bộ nhớ ngoài phần cuối của mảng. Tuy nhiên, nó cho phép một con trỏ trỏ tới một phần tử nằm ngoài phần cuối của mảng. Sự khác biệt là quan trọng.

Như vậy, đây là OK:

char array[N]; 
char *p; 
char *end; 

for (p = array, end = array + N; p < end; ++p) 
    do_something(p); 

(Làm *end sẽ là một lỗi.)

Và đó cho thấy lý do tại sao tính năng này rất hữu ích: a trỏ trỏ vào (không tồn tại) phần tử sau khi kết thúc mảng là hữu ích để so sánh, chẳng hạn như trong vòng lặp.

Về mặt kỹ thuật, đó là mọi thứ mà chuẩn C cho phép. Tuy nhiên, trong thực tế, việc triển khai C (trình biên dịch và thời gian chạy) không kiểm tra xem bạn có truy cập vào bộ nhớ ngoài phần cuối của mảng hay không, cho dù đó là một phần tử hay nhiều hơn. Sẽ phải kiểm tra giới hạn và điều đó sẽ làm chậm quá trình thực thi chương trình. Các loại chương trình C là phù hợp nhất cho (hệ thống lập trình, thư viện đa năng) có xu hướng hưởng lợi nhiều hơn từ tốc độ hơn so với kiểm tra giới hạn an ninh và an toàn sẽ cung cấp.

Điều đó có nghĩa C có lẽ không phải là công cụ tốt cho lập trình ứng dụng có mục đích chung.

15

Thông thường, nó rất hữu ích để biểu thị "kết thúc" vị trí, đó là một trong quá khứ phân bổ thực tế, vì vậy bạn có thể viết mã như:

char * end = begin + size; 
for (char * curr = begin; curr < /* or != */ end ; ++curr) { 
    /* do something in the loop */ 
} 

Tiêu chuẩn C một cách rõ ràng nói rằng yếu tố này là một hợp lệ địa chỉ bộ nhớ, nhưng dereferencing nó vẫn sẽ không được một ý tưởng tốt.

Tại sao nó có bảo lãnh này? Giả sử bạn có một máy có bộ nhớ 2^16 byte, địa chỉ 0000-FFFF, con trỏ 16 bit. Giả sử bạn đã tạo một mảng 16 byte. Bộ nhớ có thể được cấp phát tại FFF0 không?

Có 16 byte miễn phí liên tục kế nhau, nhưng:

begin + size == FFF0 + 10 (16 in hex) == 10000 

mà kết thúc tốt đẹp đến 0000 vì kích thước con trỏ. Bây giờ điều kiện vòng lặp:

curr < end == FFF0 < 0000 == false 

Thay vì lặp qua mảng, vòng lặp sẽ không làm gì cả. Điều này sẽ phá vỡ rất nhiều mã, vì vậy tiêu chuẩn C nói rằng phân bổ không được phép.

-1

bạn có thể đi xa hơn 1 quá khứ mảng cho example`

int main() 
{ 
     char *string = "string"; 
     int i = 0; 
     for(i=0; i< 10;i++) 
     { 
       printf("%c\n", string[i]); 
     } 
     return 0; 
} 

sẽ in rác sau khi kết thúc của chuỗi văn bản, bất cứ điều gì đang ngồi trong bộ nhớ trước khi tay.

+6

Nó có thể in rác, định dạng ổ đĩa cứng của bạn, hoặc gây ra quỷ để bay ra khỏi mũi của bạn; đó là bản chất của hành vi không xác định. – aib

+0

Vâng, chỉ cần đọc từ vị trí bộ nhớ là không thể định dạng ổ đĩa cứng của bạn hoặc gây ra quỷ để bay ra khỏi mũi của bạn. Viết cho nó, tuy nhiên ... –

+3

Ngay cả khi đọc một con trỏ xấu có thể khiến chương trình của bạn bị lỗi trong tương lai. Xem http://blogs.msdn.com/oldnewthing/archive/2006/09/27/773741.aspx – Eclipse

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