Thật là một câu hỏi khiêu khích!
Ngay cả chức năng quét lướt qua các câu trả lời và ý kiến trong chủ đề này sẽ tiết lộ cách dễ gây xúc động truy vấn dường như đơn giản và thẳng về phía trước của bạn hóa ra là.
Nó không đáng ngạc nhiên.
Inarguably, hiểu lầm xung quanh khái niệm và sử dụng của con trỏ đại diện cho một chủ yếu nguyên nhân nghiêm trọng thất bại trong lập trình nói chung.
Nhận thức về thực tế này là dễ thấy trong tính phổ biến của các ngôn ngữ được thiết kế đặc biệt để giải quyết, và tốt nhất là để tránh các thách thức con trỏ giới thiệu hoàn toàn. Hãy nghĩ về C ++ và các dẫn xuất khác của C, Java và các mối quan hệ của nó, Python và các tập lệnh khác - chỉ đơn thuần là những thứ nổi bật và phổ biến hơn, và ít nhiều ra lệnh xử lý vấn đề nghiêm trọng.
Phát triển sự hiểu biết sâu sắc hơn về các nguyên tắc cơ bản, do đó phải phù hợp với mọi cá nhân khao khát sự xuất sắc trong lập trình - đặc biệt là ở cấp độ hệ thống .
Tôi tưởng tượng đây là chính xác những gì giáo viên của bạn có nghĩa là để chứng minh.
Và bản chất của C làm cho nó trở thành một phương tiện thuận tiện cho việc khám phá này. Ít rõ ràng hơn lắp ráp - mặc dù có lẽ dễ hiểu hơn - và vẫn rõ ràng hơn nhiều so với các ngôn ngữ dựa trên sự trừu tượng hóa sâu hơn của môi trường thực thi.
Được thiết kế để tạo điều kiện dịch thuật xác định ý định của lập trình viên thành các hướng dẫn mà máy móc có thể hiểu, C là ngôn ngữ cấp hệ thống . Mặc dù được phân loại là cấp cao, nó thực sự thuộc về loại 'trung bình'; nhưng vì không tồn tại như vậy, nên chỉ định 'hệ thống' phải đủ.
Đặc tính này phần lớn chịu trách nhiệm biến nó thành ngôn ngữ được lựa chọn cho trình điều khiển thiết bị , mã hệ điều hành và triển khai nhúng . Hơn nữa, một sự thay thế xứng đáng được ưa chuộng trong các ứng dụng mà hiệu quả tối ưu là tối quan trọng; trong đó điều đó có nghĩa là sự khác biệt giữa sự sống còn và sự tuyệt chủng, và do đó là một điều cần thiết trái ngược với sự xa xỉ. Trong những trường hợp như vậy, sự tiện lợi hấp dẫn của tính di động sẽ mất hết sức hấp dẫn và việc chọn hiệu suất thiếu ánh sáng của mẫu số ít phổ biến nhất trở thành một lựa chọn bất lợi không thể tưởng tượng được .
Điều làm cho C - và một số dẫn xuất của nó - khá đặc biệt, là nó cho phép người dùng kiểm soát hoàn toàn - khi đó là điều họ mong muốn - mà không áp đặt các trách nhiệm liên quan lên họ khi họ không làm. Tuy nhiên, nó không bao giờ cung cấp nhiều hơn các cách điện mỏng nhất từ máy , trong đó sử dụng đúng cách đòi hỏi sự hiểu biết chính xác về khái niệm con trỏ .
Về bản chất, câu trả lời cho câu hỏi của bạn rất đơn giản và thỏa mãn ngọt ngào - để xác nhận những nghi ngờ của bạn. Cung cấp , tuy nhiên, một gắn các điều kiện tiên quyết quan trọng để mỗi khái niệm trong bản Tuyên Bố này:
- Các hành vi kiểm tra, so sánh và thao tác con trỏ luôn luôn và nhất thiết có giá trị, trong khi các kết luận rút ra từ kết quả phụ thuộc vào tính hợp lệ của các giá trị được chứa, và do đó không cần phải có.
Cái trước luôn an toàn và có khả năng thích hợp , trong khi cái trước chỉ có thể là đúng khi nó được thiết lập là an toàn . Đáng ngạc nhiên - với một số người - vì vậy việc thiết lập tính hợp lệ của cái sau phụ thuộc và đòi hỏi cái trước.
Tất nhiên, một phần của sự nhầm lẫn xuất phát từ hiệu ứng của đệ quy vốn có trong nguyên tắc của một con trỏ - và những thách thức đặt ra trong nội dung khác biệt với địa chỉ.
Bạn đã phỏng đoán khá chính xác ,
Tôi đang bị dẫn đến việc nghĩ rằng bất kỳ con trỏ nào cũng có thể được so sánh với bất kỳ con trỏ nào khác, bất kể chúng trỏ vào đâu. Hơn nữa, tôi nghĩ rằng số học con trỏ giữa hai con trỏ là tốt, bất kể chúng chỉ ở đâu bởi vì số học chỉ sử dụng bộ nhớ địa chỉ lưu trữ con trỏ.
Và một số người đóng góp đã khẳng định: con trỏ chỉ là con số. Đôi khi một cái gì đó gần hơn với số phức , nhưng vẫn không nhiều hơn số.
Sự thú vị thú vị trong đó sự tranh chấp này đã được nhận ở đây cho thấy nhiều hơn về bản chất con người hơn là lập trình, nhưng vẫn đáng lưu ý và công phu. Có lẽ chúng ta sẽ làm như vậy sau ...
Khi một bình luận bắt đầu gợi ý; tất cả sự nhầm lẫn và cấu thành này xuất phát từ nhu cầu phân biệt những gì hợp lệ từ những gì an toàn , nhưng đó là một sự đơn giản hóa. Chúng ta cũng phải phân biệt đâu là chức năng và đâu là đáng tin cậy , đâu là thực tế và những gì có thể phù hợp và hơn thế nữa: những gì phù hợp trong một hoàn cảnh cụ thể với những gì có thể phù hợp theo nghĩa chung hơn . Chưa kể; sự khác biệt giữa sự phù hợp và quyền sở hữu .
Để đạt được điều đó, trước tiên chúng ta cần đánh giá chính xác con trỏ là gì .
- Bạn đã chứng minh một khái niệm vững chắc về khái niệm này, và giống như một số người khác có thể thấy những minh họa này đơn giản hóa, nhưng mức độ nhầm lẫn rõ ràng ở đây đòi hỏi sự đơn giản như vậy trong việc làm rõ.
Như nhiều người đã chỉ ra: con trỏ thuật ngữ chỉ là một tên đặc biệt cho những gì đơn giản là một chỉ mục , và do đó không có gì nhiều hơn bất kỳ số nào khác .
Điều này nên đã được tự hiển nhiên trong việc xem xét thực tế là tất cả các máy tính chủ đạo hiện đại là máy nhị phân mà nhất thiết phải làm việc độc quyền với và số . Điện toán lượng tử có thể thay đổi điều đó, nhưng điều đó rất khó xảy ra, và nó chưa đến tuổi.
Về mặt kỹ thuật, như bạn đã lưu ý, con trỏ là địa chỉ chính xác hơn ; một cái nhìn sâu sắc rõ ràng giới thiệu một cách tự nhiên sự tương đồng bổ ích của việc tương quan chúng với 'địa chỉ' của những ngôi nhà, hoặc những mảnh đất trên đường phố.
Trong mô hình bộ nhớ phẳng : toàn bộ bộ nhớ hệ thống được sắp xếp theo một chuỗi tuyến tính duy nhất: tất cả các ngôi nhà trong thành phố nằm trên cùng một con đường và mỗi ngôi nhà chỉ được xác định duy nhất bởi số lượng của nó. Rất đơn giản.
Trong các sơ đồ được phân đoạn : một tổ chức phân cấp của các con đường được đánh số được giới thiệu ở trên các ngôi nhà được đánh số để các địa chỉ tổng hợp được yêu cầu.
- Một số triển khai vẫn còn phức tạp hơn và tổng số 'đường' riêng biệt không cần phải kết hợp với một chuỗi liền kề, nhưng không có gì thay đổi bất cứ điều gì về bên dưới.
- Chúng tôi nhất thiết có thể phân tách mọi liên kết phân cấp như vậy trở lại thành một tổ chức phẳng. Tổ chức càng phức tạp, chúng ta sẽ càng phải nhảy qua nhiều vòng để làm như vậy, nhưng nó phải có thể. Thật vậy, điều này cũng áp dụng cho 'chế độ thực' trên x86.
- Mặt khác, việc ánh xạ các liên kết đến các vị trí sẽ không mang tính phỏng đoán , vì việc thực thi đáng tin cậy - ở cấp độ hệ thống - đòi hỏi nó PHẢI .
- nhiều địa chỉ không được ánh xạ tới các vị trí bộ nhớ số ít và
- địa chỉ số ít phải không bao giờ ánh xạ tới nhiều vị trí bộ nhớ.
Đưa chúng ta đến bước ngoặt xa hơn biến câu hỏi hóc búa thành một mớ phức tạp hấp dẫn như vậy . Ở trên, nó đã được thiết kế để gợi ý rằng con trỏ là địa chỉ, vì mục đích đơn giản và rõ ràng. Tất nhiên, điều này là không chính xác. Một con trỏ là không một địa chỉ; một con trỏ là một tham chiếu đến một địa chỉ , nó chứa một địa chỉ . Giống như phong bì thể thao một tài liệu tham khảo cho ngôi nhà. Suy ngẫm về điều này có thể khiến bạn nhìn thoáng qua ý nghĩa của gợi ý đệ quy có trong khái niệm này. Vẫn; chúng tôi chỉ có rất nhiều từ và nói về địa chỉ của các tham chiếu đến địa chỉvà như vậy, sớm ngăn chặn hầu hết các bộ não ở một ngoại lệ mã không hợp lệ . Và phần lớn, ý định dễ dàng được thu thập từ bối cảnh, vì vậy chúng ta hãy trở lại đường phố.
Nhân viên bưu điện ở thành phố tưởng tượng này của chúng ta rất giống với những người chúng ta tìm thấy trong thế giới 'thực'. Không ai có khả năng bị đột quỵ khi bạn nói chuyện hoặc hỏi thăm về một địa chỉ không hợp lệ , nhưng mỗi người cuối cùng sẽ chùn bước khi bạn yêu cầu họ hành động dựa trên thông tin đó.
Giả sử chỉ có 20 ngôi nhà trên đường phố số ít của chúng tôi. Giả vờ thêm rằng một số linh hồn sai lầm, hoặc mắc chứng khó đọc đã gửi một lá thư, một điều rất quan trọng, đến số 71. Bây giờ, chúng ta có thể hỏi người vận chuyển Frank của chúng tôi, liệu có địa chỉ như vậy không, và anh ta sẽ báo cáo một cách đơn giản và bình tĩnh: không . Chúng tôi thậm chí có thể hy vọng anh ta ước tính có bao xa bên ngoài đường phố vị trí này sẽ nằm nếu nó đã tồn tại: xấp xỉ 2,5 lần xa hơn cuối cùng. Không ai trong số này sẽ gây ra cho anh ta bất kỳ sự bực tức. Tuy nhiên, nếu chúng tôi yêu cầu anh ta chuyển bức thư này, hoặc nhặt một món đồ từ nơi đó, anh ta có thể sẽ khá thẳng thắn về sự không hài lòng của anh ta , và từ chối tuân thủ.
Con trỏ là chỉ địa chỉ và địa chỉ là chỉ số.
Xác nhận đầu ra của các mục sau:
void foo( void *p ) {
printf(“%p\t%zu\t%d\n”, p, (size_t)p, p == (size_t)p);
}
Gọi nó trên bao nhiêu con trỏ tùy thích, hợp lệ hay không. Xin vui lòng làm gửi phát hiện của bạn nếu nó không thành công trên nền tảng của bạn, hoặc bạn (hiện đại) biên dịch phàn nàn.
Bây giờ, vì con trỏ là chỉ đơn giản là con số, nó là chắc chắn có giá trị để so sánh chúng. Theo một nghĩa nào đó thì đây chính xác là những gì giáo viên của bạn đang thể hiện. Tất cả các tuyên bố sau là hoàn toàn hợp lệ - và đúng! - C và khi được biên dịch sẽ chạy mà không gặp phải sự cố , mặc dù không phải con trỏ nào cũng cần được khởi tạo và do đó các giá trị chúng chứa có thể không được xác định :
- Chúng tôi chỉ tính toán
result
rõ ràng vì mục đích rõ ràng và in nó để buộc trình biên dịch tính toán những gì sẽ là dự phòng, mã chết.
void foo( size_t *a, size_t *b ) {
size_t result;
result = (size_t)a;
printf(“%zu\n”, result);
result = a == b;
printf(“%zu\n”, result);
result = a < b;
printf(“%zu\n”, result);
result = a - b;
printf(“%zu\n”, result);
}
Tất nhiên, chương trình không được định dạng khi a hoặc b không được xác định (đọc: không được khởi tạo đúng cách ) tại điểm kiểm tra, nhưng điều đó hoàn toàn không liên quan đến phần thảo luận này của chúng tôi. Các đoạn mã này, cũng như các tuyên bố sau, được đảm bảo - theo 'tiêu chuẩn' - để biên dịch và chạy hoàn hảo, bất chấp tính hiệu lực IN của bất kỳ con trỏ nào có liên quan.
Các vấn đề chỉ phát sinh khi một con trỏ không hợp lệ bị hủy đăng ký . Khi chúng tôi yêu cầu Frank nhận hoặc giao hàng tại địa chỉ không hợp lệ, không tồn tại.
Cho bất kỳ con trỏ tùy ý:
int *p;
Trong khi tuyên bố này phải biên dịch và chạy:
printf(“%p”, p);
... như phải thế này:
size_t foo( int *p ) { return (size_t)p; }
... sau hai, hoàn toàn trái ngược, sẽ vẫn dễ dàng biên dịch, nhưng thất bại trong thực hiện trừ khi con trỏ là hợp lệ - mà chúng ta ở đây chỉ có nghĩa là nó tham chiếu một địa chỉ để mà ứng dụng hiện nay đã được cấp quyền truy cập :
printf(“%p”, *p);
size_t foo( int *p ) { return *p; }
Làm thế nào tinh tế thay đổi? Sự khác biệt nằm ở sự khác biệt giữa giá trị của con trỏ - đó là địa chỉ và giá trị của nội dung: của ngôi nhà ở số đó. Không có vấn đề phát sinh cho đến khi con trỏ là dereferenced ; cho đến khi một nỗ lực được thực hiện để truy cập vào địa chỉ mà nó liên kết đến. Trong khi cố gắng giao hàng hoặc nhận gói hàng vượt ra khỏi đoạn đường ...
Bằng cách mở rộng, cùng một nguyên tắc nhất thiết phải áp dụng cho các ví dụ phức tạp hơn, bao gồm cả nhu cầu đã nói ở trên để thiết lập tính hợp lệ cần thiết:
int* validate( int *p, int *head, int *tail ) {
return p >= head && p <= tail ? p : NULL;
}
So sánh quan hệ và số học cung cấp tiện ích giống hệt nhau để kiểm tra tính tương đương và có giá trị tương đương - về nguyên tắc. Tuy nhiên , những gì kết quả của tính toán như vậy sẽ biểu thị , là một vấn đề hoàn toàn khác - và chính xác là vấn đề được giải quyết bằng các trích dẫn bạn đưa vào.
Trong C, một mảng là một bộ đệm liền kề, một chuỗi các vị trí bộ nhớ tuyến tính không bị gián đoạn. So sánh và số học áp dụng cho các con trỏ mà các vị trí tham chiếu trong một chuỗi số ít như vậy là tự nhiên và rõ ràng có ý nghĩa liên quan đến cả hai và với 'mảng' này (được xác định đơn giản bởi cơ sở). Chính xác như vậy áp dụng cho mọi khối được phân bổ thông qua malloc
, hoặc sbrk
. Vì các mối quan hệ này là ẩn , trình biên dịch có thể thiết lập các mối quan hệ hợp lệ giữa chúng và do đó có thể tin tưởng rằng các tính toán sẽ cung cấp các câu trả lời dự đoán.
Thực hiện các bài thể dục tương tự trên các con trỏ tham chiếu các khối hoặc mảng riêng biệt không cung cấp bất kỳ tiện ích vốn có và rõ ràng như vậy . Hơn nữa vì bất cứ mối quan hệ nào tồn tại tại một thời điểm có thể bị vô hiệu hóa bởi sự phân bổ lại theo sau, trong đó có khả năng thay đổi cao, thậm chí bị đảo ngược. Trong các trường hợp như vậy, trình biên dịch không thể có được thông tin cần thiết để thiết lập độ tin cậy của nó trong tình huống trước đó.
Bạn , tuy nhiên, là lập trình viên, có thể có kiến thức như vậy! Và trong một số trường hợp có nghĩa vụ khai thác điều đó.
Có LÀ Do đó, trường hợp trong đó ngay cả điều này là hoàn toàn hợp lệ và hoàn hảo PROPER.
Trên thực tế, đó chính xác là những gì malloc
bản thân phải làm trong nội bộ khi đến lúc thử hợp nhất các khối khai hoang - trên phần lớn các kiến trúc. Điều tương tự cũng đúng với bộ cấp phát hệ điều hành, như thế đằng sau sbrk
; nếu rõ ràng hơn , thường xuyên hơn , trên các thực thể khác nhau hơn , quan trọng hơn - và cũng có liên quan trên các nền tảng nơi điều này malloc
có thể không. Và có bao nhiêu trong số đó không được viết bằng C?
Tính hợp lệ, bảo mật và thành công của một hành động chắc chắn là hệ quả của mức độ hiểu biết mà nó được đặt ra và áp dụng.
Trong các trích dẫn bạn đã đưa ra, Kernighan và Ritchie đang giải quyết một vấn đề riêng biệt, nhưng dù sao cũng có liên quan. Họ đang xác định các giới hạn của ngôn ngữ và giải thích cách bạn có thể khai thác các khả năng của trình biên dịch để bảo vệ bạn bằng cách ít nhất phát hiện các cấu trúc có khả năng bị lỗi. Họ đang mô tả độ dài mà cơ chế có thể - được thiết kế - để đi đến để hỗ trợ bạn trong công việc lập trình. Trình biên dịch là đầy tớ của bạn, bạn là chủ. Tuy nhiên, một bậc thầy thông thái là một người quen thuộc với khả năng của những người hầu khác nhau.
Trong bối cảnh này, hành vi không xác định phục vụ để chỉ ra nguy cơ tiềm ẩn và khả năng gây hại; không ngụ ý sắp xảy ra, cam chịu không thể đảo ngược, hoặc kết thúc của thế giới như chúng ta biết. Nó đơn giản có nghĩa là chúng tôi - 'có nghĩa là trình biên dịch' - không thể đưa ra bất kỳ phỏng đoán nào về vấn đề này có thể là gì, hoặc đại diện và vì lý do này, chúng tôi chọn rửa tay về vấn đề này. Chúng tôi sẽ không chịu trách nhiệm cho bất kỳ sai sót nào có thể xảy ra do việc sử dụng hoặc sử dụng sai mục đích của cơ sở này .
Trong thực tế, nó chỉ đơn giản nói: 'Ngoài thời điểm này, cao bồi : bạn đang ở một mình ...'
Giáo sư của bạn đang tìm cách thể hiện các sắc thái tốt hơn cho bạn.
Lưu ý những gì họ đã quan tâm rất nhiều trong việc xây dựng ví dụ của họ; và làm thế nào giòn nó vẫn là. Bằng cách lấy địa chỉ của a
, trong
p[0].p0 = &a;
trình biên dịch bị ép buộc phân bổ lưu trữ thực tế cho biến, thay vì đặt nó trong một thanh ghi. Nó là một biến tự động, tuy nhiên, lập trình viên không có quyền kiểm soát nơi được gán và do đó không thể đưa ra bất kỳ phỏng đoán hợp lệ nào về những gì sẽ theo nó. Đó là lý do tại sao a
phải được đặt bằng 0 để mã hoạt động như mong đợi.
Chỉ thay đổi dòng này:
char a = 0;
đến đây:
char a = 1; // or ANY other value than 0
làm cho hành vi của chương trình trở nên không xác định . Tối thiểu, câu trả lời đầu tiên bây giờ sẽ là 1; nhưng vấn đề còn độc ác hơn nhiều.
Bây giờ mã đang mời gọi của thảm họa.
Mặc dù vẫn hoàn toàn hợp lệ và thậm chí tuân thủ tiêu chuẩn , nhưng hiện tại nó không được định dạng và mặc dù chắc chắn để biên dịch, có thể thất bại trong việc thực thi trên nhiều lý do khác nhau. Còn bây giờ có rất nhiều vấn đề - không trong đó trình biên dịch là khả năng để nhận ra.
strcpy
sẽ bắt đầu tại địa chỉ của a
và tiến hành vượt quá mức này để tiêu thụ - và chuyển - byte sau byte, cho đến khi nó gặp null.
Con p1
trỏ đã được khởi tạo thành một khối chính xác là 10 byte.
Nếu a
tình cờ được đặt ở cuối một khối và quá trình không có quyền truy cập vào phần tiếp theo, thì lần đọc tiếp theo - của p0 [1] - sẽ gợi ra một segfault. Kịch bản này không thể xảy ra trên kiến trúc x86, nhưng có thể.
Nếu khu vực nằm ngoài địa chỉ a
có thể truy cập, sẽ không xảy ra lỗi đọc, nhưng chương trình vẫn không được lưu khỏi điều không may.
Nếu một byte 0 xảy ra trong mười bắt đầu tại địa chỉ của a
nó, thì nó vẫn có thể tồn tại, sau đóstrcpy
sẽ dừng lại và ít nhất chúng ta sẽ không bị vi phạm ghi.
Nếu nó không bị lỗi khi đọc amiss, nhưng không có byte 0 nào xảy ra trong khoảng 10 này, strcpy
sẽ tiếp tục và cố gắng ghi vượt ra ngoài khối được phân bổ bởi malloc
.
Nếu khu vực này không thuộc sở hữu của quy trình, segfault sẽ được kích hoạt ngay lập tức.
Vẫn tai hại hơn - và tinh tế --- tình huống phát sinh khi khối sau đây là thuộc sở hữu của quá trình này, cho thì lỗi không thể được phát hiện, không có tín hiệu có thể được nâng lên, và vì vậy nó có thể 'xuất hiện' vẫn 'làm việc' , trong khi nó thực sự sẽ ghi đè lên dữ liệu khác, cấu trúc quản lý của người cấp phát hoặc thậm chí mã (trong các môi trường hoạt động nhất định).
Đây là lý do tại sao con trỏ liên quan lỗi có thể rất khó để theo dõi . Hãy tưởng tượng những dòng này được chôn sâu trong hàng ngàn dòng mã liên quan phức tạp, mà người khác đã viết và bạn được hướng dẫn để tìm hiểu kỹ.
Tuy nhiên , chương trìnhvẫn phải biên dịch, vì nó vẫn hoàn toàn hợp lệ và tuân thủ tiêu chuẩn C.
Những loại lỗi, không có tiêu chuẩn và không có trình biên dịch có thể bảo vệ sự không sẵn sàng chống lại. Tôi tưởng tượng đó chính xác là những gì họ đang có ý định dạy bạn.
Người hoang tưởng liên tục tìm cách thay đổi các tính chất của C để xử lý những khả năng có vấn đề và do đó cứu chúng ta khỏi chính mình; nhưng đó là không lịch sự . Đây là trách nhiệm chúng tôi có nghĩa vụ phải chấp nhận khi chúng tôi chọn theo đuổi quyền lực và có được sự tự do mà sự kiểm soát trực tiếp và toàn diện hơn của máy mang lại cho chúng tôi. Những người quảng bá và theo đuổi sự hoàn hảo trong hiệu suất sẽ không bao giờ chấp nhận bất cứ điều gì ít hơn.
Tính di động và tính tổng quát mà nó thể hiện là một sự xem xét cơ bản riêng biệt và tất cả những gì tiêu chuẩn tìm cách giải quyết:
Tài liệu này chỉ định biểu mẫu và thiết lập việc giải thích các chương trình được thể hiện bằng ngôn ngữ lập trình C. Mục đích của nó là thúc đẩy tính di động , độ tin cậy, khả năng bảo trì và thực thi hiệu quả các chương trình ngôn ngữ C trên nhiều hệ thống máy tính .
Đó là lý do tại sao nó hoàn toàn đúng đắn để giữ cho nó khác biệt với định nghĩa và đặc điểm kỹ thuật của chính ngôn ngữ. Trái ngược với những gì nhiều người dường như tin rằng tính tổng quát là phản đối với ngoại lệ và mẫu mực .
Để kết luận:
- Tự kiểm tra và thao tác con trỏ là hợp lệ và thường có kết quả . Giải thích các kết quả, có thể, hoặc có thể không có ý nghĩa, nhưng tai họa không bao giờ được mời đến khi con trỏ được dereferenced ; cho đến khi một nỗ lực được thực hiện để truy cập vào địa chỉ được liên kết đến.
Điều này không đúng, lập trình như chúng ta biết - và yêu nó - sẽ không thể thực hiện được.
C
với những gì là an toàn trongC
. Tuy nhiên, việc so sánh hai con trỏ với cùng loại có thể được thực hiện (ví dụ: kiểm tra sự bằng nhau), bằng cách sử dụng số học con trỏ và so sánh>
và<
chỉ an toàn khi được sử dụng trong một mảng nhất định (hoặc khối bộ nhớ).