Các câu trả lời sớm hơn có vẻ thiếu ngữ cảnh và không giải quyết thuộc tính mà con trỏ C bị quá tải. Hoàn toàn công bằng khi tuyên bố rằng C "đi qua tham chiếu". Con trỏ cũng là một tham chiếu. Tuy nhiên, chính thức hơn, một tham chiếu C là cơ chế biểu diễn địa chỉ bộ nhớ của ký hiệu.
- Con trỏ chỉ đơn giản là biến trong bộ nhớ có giá trị được coi là địa chỉ .
- Tham chiếu chỉ đơn giản là giá trị theo nghĩa đen cho địa chỉ bộ nhớ.
- Ngôn ngữ C cho phép truyền qua tham chiếu - nhưng chỉ trong ngữ cảnh phù hợp!
Tách ngữ cảnh là định nghĩa chữ ký và lời gọi chữ ký.
Hãy xem xét nguyên thủy int a = 0x22e8;
và một nơi khác mà chúng tôi khai báo int* b = &a;
(Tôi sẽ nhận được chức năng sau một phút).
Chúng ta có thể hình dung việc này mà nhớ (giả định endianness không quan trọng ví dụ này):
...
0x00000200: 22e8 ; this is the variable for int a's literal value:
; a == 0x000022e8
; &a == 0x00000200
0x00000???: 9090 ; ... more code ...
0x00000400: 0200 ; this is pointer b pointing to a's address:
; b == 0x00000200
; *b == 0x000022e8
; &b == 0x00000400
...
Thật dễ dàng để thấy rằng chúng ta có thể gán một con trỏ đến bất kỳ địa chỉ mà không cần bất kỳ thủ thuật đặc biệt. Một con trỏ chỉ là một biến, nhưng C cho phép chúng ta tham chiếu đến địa chỉ mà nó trỏ đến; chúng ta có thể "dereference" con trỏ từ địa chỉ giá trị của nó để thay thế coi con trỏ là giá trị cơ bản của con trỏ trong một ngữ cảnh yêu cầu: while (*b == a) ...
. Chúng ta có thể dễ dàng gọi b == &a
.
Khi áp dụng tính năng này để thực hiện cuộc gọi, bạn phải tách biệt ngữ cảnh của hàm (chữ ký) định nghĩa so với yêu cầu để phân biệt đường truyền theo tham chiếu.
int* foo(int* blah, int nah) { .. } // signature definition context:
// These are parameters
... vs ...
b = foo(&a, 4); // invocation context:
// These are arguments
Trong việc xác định một chữ ký chức năng, chúng tôi không nói với trình biên dịch mà giải quyết một cuộc tranh cãi được truy cập từ — thời gian chạy thậm chí chưa biết! Nó chỉ là vô nghĩa để xác định void bar(int &blah) {...}
. Thay vào đó, chúng tôi sử dụng cú pháp con trỏ bị bỏ qua — "bất kỳ đối số nào được truyền vào sẽ được tải tại địa chỉ được trỏ tới" — để tham chiếu giá trị đối số mong muốn khi thời gian chạy xảy ra. Như vậy C có thể truyền tham số bằng tham chiếu.
Ngữ cảnh của cả hai định nghĩa chữ ký hàm và các cuộc gọi hàm thay đổi cách trình biên dịch xem xét quá tải con trỏ so với tham chiếu và cách thời gian chạy thực sự có thể giải quyết chúng.
Tại sao bạn nghĩ rằng đi qua tham chiếu nên làm việc trong C?C không có tham chiếu. –
Chắc chắn rồi. Nó chỉ gọi tham chiếu của nó là "con trỏ". – Crashworks
"con trỏ" không được "chuyển bằng tham chiếu". Bất cứ điều gì bạn chuyển đến một hàm trong C, nó được truyền theo giá trị. Nó có thể xảy ra rằng thứ được truyền qua là con trỏ, trong trường hợp này, hàm nhận được * bản sao của con trỏ * và có thể sử dụng bản sao đó để thay đổi giá trị được trỏ tới bởi con trỏ, nhưng chính con trỏ được truyền theo giá trị . –