Представленные ранее ответы, похоже, не содержат контекста и не учитывают свойство, которое указатели C перегружены. Совершенно справедливо утверждать, что C «проходит по ссылке». Указатель также является ссылкой. Однако, более формально, «ссылка» на C - это механизм для представления адреса памяти символа.
- Указатель - это просто переменная в памяти, значение которой рассматривается как
адрес.
- Ссылка - это просто литерал значения для адреса памяти.
- Язык C позволяет передавать по ссылке - но только в правильном контексте!
Разделение контекста - это разделение определения подписи и вызова подписи.
Рассмотрим примитивы int a = 0x22e8;
и где-то еще мы объявляем int* b = &a;
(через минуту я доберусь до функций).
Мы могли бы визуализировать это в памяти (предположим, что порядковый номер не имеет значения для этого примера):
...
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
...
Легко видеть, что мы можем назначить указатель на любой адрес без каких-либо специальных уловок. Указатель - это просто переменная, но C позволяет нам ссылаться на адрес, на который он указывает; мы можем «разыменовать» указатель от его значения-адреса, чтобы вместо этого рассматривать указатель как базовое значение его указателя во время контекста вызова: while ( *b == a ) ...
. Мы могли бы легко вызвать b == &a
.
При применении этого к вызовам функций, вы должны отделить контекст определения функции (подписи) от вызова, чтобы дифференцировать передачу по ссылке.
int* foo(int* blah, int nah) { .. } // signature definition context:
// These are parameters
... vs ...
b = foo( &a, 4); // invocation context:
// These are arguments
При определении сигнатуры функции мы не сообщаем компилятору, какой адрес аргумента доступен из & mdash; время выполнения еще даже не знает! Это просто глупость определять void bar(int &blah) {...}
. Вместо этого мы используем синтаксис разыменованного указателя & mdash; msgstr "любой передаваемый аргумент будет загружен по адресу, указанному в" & mdash; для ссылки на желаемое значение аргумента, когда происходит время выполнения. Таким образом, C может передавать аргументы по ссылке.
Контексты как определений сигнатур функций, так и вызовов функций изменяют то, как компилятор смотрит на перегрузку указателей по сравнению со ссылками, и как среда выполнения может их реально решать.