Tôi đã có niềm vui gần đây để giải thích con trỏ cho người mới bắt đầu lập trình C và vấp phải khó khăn sau đây. Có vẻ như đây không phải là vấn đề nếu bạn đã biết cách sử dụng con trỏ, nhưng hãy thử xem ví dụ sau với một tâm trí rõ ràng:
int foo = 1;
int *bar = &foo;
printf("%p\n", (void *)&foo);
printf("%i\n", *bar);
Đối với người mới bắt đầu tuyệt đối, đầu ra có thể gây ngạc nhiên. Trong dòng 2 anh ấy / cô ấy vừa tuyên bố * thanh là & foo, nhưng ở dòng 4 thì hóa ra * thanh thực sự là foo thay vì & foo!
Sự nhầm lẫn, bạn có thể nói, xuất phát từ sự mơ hồ của biểu tượng *: Trong dòng 2, nó được sử dụng để khai báo một con trỏ. Trong dòng 4, nó được sử dụng như một toán tử đơn nguyên tìm nạp giá trị mà con trỏ trỏ tới. Hai điều khác nhau, phải không?
Tuy nhiên, "lời giải thích" này không giúp ích gì cho người mới bắt đầu cả. Nó giới thiệu một khái niệm mới bằng cách chỉ ra sự khác biệt tinh tế. Đây không thể là cách đúng đắn để dạy nó.
Vậy, Kernighan và Ritchie đã giải thích nó như thế nào?
Toán tử unary * là toán tử indirection hoặc dereferences; khi được áp dụng cho một con trỏ, nó truy cập vào đối tượng mà con trỏ trỏ tới. [Càng]
Việc khai báo ip con trỏ,
int *ip
được dự định là một bản ghi nhớ; nó nói rằng biểu thức*ip
là một int. Cú pháp khai báo cho một biến bắt chước cú pháp của các biểu thức trong đó biến có thể xuất hiện .
int *ip
nên được đọc như " *ip
sẽ trả lại một int
"? Nhưng tại sao sau đó không chuyển nhượng sau khi khai báo theo mô hình đó? Điều gì xảy ra nếu một người mới bắt đầu muốn khởi tạo biến? int *ip = 1
(đọc: *ip
sẽ trả lại một int
và int
là 1
) sẽ không hoạt động như mong đợi. Mô hình khái niệm không có vẻ mạch lạc. Am i thiếu cái gì ở đây?
Chỉnh sửa: Nó đã cố gắng tóm tắt các câu trả lời ở đây .
*
trong một khai báo là một mã thông báo có nghĩa là "khai báo một con trỏ", trong biểu thức đó là toán tử quy ước và hai biểu thức này đại diện cho những điều khác nhau có cùng một biểu tượng (giống như toán tử nhân - cùng ký hiệu, nghĩa khác nhau). Thật khó hiểu, nhưng bất cứ điều gì khác với tình trạng thực tế sẽ còn tồi tệ hơn.
int* bar
làm cho rõ ràng hơn rằng ngôi sao thực sự là một phần của loại, không phải là một phần của định danh. Tất nhiên điều này đưa bạn vào những vấn đề khác nhau với những thứ không trực quan như thế nào int* a, b
.
*
có thể có hai ý nghĩa khác nhau tùy thuộc vào ngữ cảnh. Giống như cùng một chữ cái có thể được phát âm khác nhau tùy thuộc vào từ đó khiến cho việc học nói nhiều ngôn ngữ trở nên khó khăn. Nếu mỗi khái niệm / hoạt động đơn lẻ có biểu tượng riêng, chúng ta sẽ cần bàn phím lớn hơn nhiều, vì vậy các biểu tượng được tái chế khi có ý nghĩa để làm như vậy.
int* p
), đồng thời cảnh báo học sinh của bạn không sử dụng nhiều khai báo trong cùng một dòng khi con trỏ có liên quan. Khi học sinh đã hoàn toàn hiểu khái niệm con trỏ, hãy giải thích cho học sinh rằng int *p
cú pháp là tương đương và sau đó giải thích vấn đề bằng nhiều khai báo.