Các câu trả lời khác là đúng, nhưng không ai trong số họ nhấn mạnh ý tưởng rằng cả ba đều có thể chứa cùng một giá trị , và vì vậy chúng theo một cách nào đó không đầy đủ.
Lý do điều này không thể hiểu được từ các câu trả lời khác là vì tất cả các minh họa, trong khi hữu ích và chắc chắn hợp lý trong hầu hết các trường hợp, không bao gồm tình huống mà con trỏ x
chỉ vào chính nó.
Điều này là khá dễ dàng để xây dựng, nhưng rõ ràng là một chút khó hiểu. Trong chương trình bên dưới, chúng ta sẽ thấy làm thế nào chúng ta có thể buộc cả ba giá trị giống hệt nhau.
LƯU Ý: Hành vi trong chương trình này không được xác định, nhưng tôi đăng nó ở đây hoàn toàn là một minh chứng thú vị về những điều mà con trỏ có thể làm, nhưng không nên .
#include <stdio.h>
int main () {
int *(*x)[5];
x = (int *(*)[5]) &x;
printf("%p\n", x[0]);
printf("%p\n", x[0][0]);
printf("%p\n", x[0][0][0]);
}
Điều này biên dịch mà không có cảnh báo trong cả C89 và C99, và đầu ra là như sau:
$ ./ptrs
0xbfd9198c
0xbfd9198c
0xbfd9198c
Thật thú vị, cả ba giá trị là giống hệt nhau. Nhưng điều này không phải là một bất ngờ! Đầu tiên, hãy chia nhỏ chương trình.
Chúng tôi khai báo x
là một con trỏ tới một mảng gồm 5 phần tử trong đó mỗi phần tử thuộc kiểu con trỏ tới int. Tuyên bố này phân bổ 4 byte trên ngăn xếp thời gian chạy (hoặc nhiều hơn tùy thuộc vào việc triển khai của bạn; trên con trỏ máy của tôi là 4 byte), do đó, x
đề cập đến một vị trí bộ nhớ thực tế. Trong họ ngôn ngữ C, nội dung x
chỉ là rác, thứ gì đó còn sót lại từ việc sử dụng vị trí trước đó, vì vậy x
bản thân nó không chỉ ra bất cứ nơi nào mà chắc chắn không phân bổ không gian.
Vì vậy, một cách tự nhiên, chúng ta có thể lấy địa chỉ của biến x
và đặt nó ở đâu đó, vì vậy đó chính xác là những gì chúng ta làm. Nhưng chúng ta sẽ tiếp tục và đặt nó vào x chính nó. Vì &x
có một loại khác vớix
, chúng tôi cần thực hiện một vai diễn để chúng tôi không nhận được cảnh báo.
Mô hình bộ nhớ sẽ trông giống như thế này:
0xbfd9198c
+------------+
| 0xbfd9198c |
+------------+
Vì vậy, khối bộ nhớ 4 byte tại địa chỉ 0xbfd9198c
chứa mẫu bit tương ứng với giá trị thập lục phân 0xbfd9198c
. Đủ đơn giản.
Tiếp theo, chúng tôi in ra ba giá trị. Các câu trả lời khác giải thích những gì mỗi biểu thức đề cập đến, vì vậy mối quan hệ nên rõ ràng ngay bây giờ.
Chúng ta có thể thấy rằng các giá trị là như nhau, nhưng chỉ ở mức độ rất thấp ... các mẫu bit của chúng giống hệt nhau, nhưng dữ liệu loại được liên kết với mỗi biểu thức có nghĩa là các giá trị được giải thích của chúng là khác nhau. Chẳng hạn, nếu chúng tôi in ra x[0][0][0]
bằng chuỗi định dạng%d
, chúng ta sẽ nhận được một số âm rất lớn, do đó, "các giá trị" trên thực tế là khác nhau, nhưng mẫu bit là như nhau.
Điều này thực sự rất đơn giản ... trong các sơ đồ, các mũi tên chỉ vào cùng một địa chỉ bộ nhớ chứ không phải là các địa chỉ khác nhau. Tuy nhiên, trong khi chúng tôi có thể buộc một kết quả mong đợi từ hành vi không xác định, thì đó chỉ là điều không xác định. Đây không phải là mã sản xuất mà chỉ đơn giản là một minh chứng cho mục đích hoàn thiện.
Trong một tình huống hợp lý, bạn sẽ sử dụng malloc
để tạo mảng 5 con trỏ int và một lần nữa để tạo các int được trỏ đến trong mảng đó.malloc
luôn trả về một địa chỉ duy nhất (trừ khi bạn hết bộ nhớ, trong trường hợp đó, nó trả về NULL hoặc 0), vì vậy bạn sẽ không bao giờ phải lo lắng về các con trỏ tự giới thiệu như thế này.
Hy vọng rằng đó là câu trả lời đầy đủ mà bạn đang tìm kiếm. Bạn không nên mong đợi x[0]
, x[0][0]
và x[0][0][0]
bằng nhau, nhưng chúng có thể là nếu bị ép buộc. Nếu bất cứ điều gì đi qua đầu của bạn, cho tôi biết để tôi có thể làm rõ!
x[0]
,x[0][0]
vàx[0][0][0]
có nhiều loại khác nhau. Họ không thể được so sánh. Bạn có ý nghĩa!=
gì?