Если C не поддерживает передачу переменной по ссылке, почему это работает?
#include <stdio.h>
void f(int *j) {
(*j)++;
}
int main() {
int i = 20;
int *p = &i;
f(p);
printf("i = %d\n", i);
return 0;
}
Вывод:
$ gcc -std=c99 test.c
$ a.exe
i = 21
&
) перед вызовом функции и явно разыменовать ее (с*
) в функции.f(&i);
это реализация передачи по ссылке, которой нет просто в C. C передача по ссылкеОтветы:
Потому что вы передаете значение указателя методу, а затем разыменовываете его, чтобы получить целое число, на которое указывает указатель.
источник
func
:func(&A);
это передало бы указатель на A функции, не копируя что-либо вообще. Это передача по значению, но это значение является ссылкой, поэтому вы 'передаете по ссылке' переменную A. Копирование не требуется. Это справедливо сказать, что это передача по ссылке.Это не передача по ссылке, это передача по значению, как заявили другие.
Правило следующее:
Давайте попробуем увидеть разницу между скалярными и указательными параметрами функции.
Скалярные переменные
Эта короткая программа показывает передачу по значению с использованием скалярной переменной.
param
называется формальным параметром иvariable
при вызове функции называется фактическим параметром. Приращение примечанияparam
в функции не изменяетсяvariable
.Результат
Иллюзия передачи по ссылке
Мы немного изменили кусок кода.
param
указатель сейчасРезультат
Это заставляет вас поверить, что параметр был передан по ссылке. Не было. Он был передан по значению, а значение параметра является адресом. Значение типа int было увеличено, и это побочный эффект, который заставляет нас думать, что это был вызов функции передачи по ссылке.
Указатели - передаваемые по значению
Как мы можем показать / доказать этот факт? Ну, может быть, мы можем попробовать первый пример скалярных переменных, но вместо скалярных мы используем адреса (указатели). Посмотрим, может ли это помочь.
Результатом будет то, что два адреса равны (не беспокойтесь о точном значении).
Пример результата:
На мой взгляд, это ясно показывает, что указатели передаются по значению. В противном случае
ptr
будетNULL
после вызова функции.источник
Источник: www-cs-students.stanford.edu
источник
Потому что в приведенном выше коде нет передачи по ссылке. Использование указателей (таких как
void func(int* p)
) является передачей по адресу. Это передача по ссылке в C ++ (не будет работать в C):источник
Ваш пример работает, потому что вы передаете адрес вашей переменной в функцию, которая манипулирует ее значением с помощью оператора разыменования .
Пока C не поддерживает ссылочные типы данных , вы все равно можете имитировать передачу по ссылке, явно передавая значения указателя, как в вашем примере.
Ссылочный тип данных C ++ менее мощный, но считается более безопасным, чем тип указателя, унаследованный от C. Это будет ваш пример, адаптированный для использования ссылок C ++ :
источник
Вы передаете указатель (адрес) по значению .
Это все равно что сказать «вот место с данными, которые я хочу, чтобы вы обновили».
источник
р является переменной указателя. Его значением является адрес i. Когда вы вызываете f, вы передаете значение p, которое является адресом i.
источник
Нет передачи по ссылке в C, но p «ссылается» на i, и вы передаете p по значению.
источник
В C все передается по значению. Использование указателей дает нам иллюзию, что мы передаем по ссылке, потому что значение переменной изменяется. Однако, если вы распечатаете адрес переменной-указателя, вы увидите, что это не влияет. Копия от значения адреса передается в функцию. Ниже приведен фрагмент, иллюстрирующий это.
источник
Потому что вы передаете указатель (адрес памяти) на переменную p в функцию f. Другими словами, вы передаете указатель, а не ссылку.
источник
Краткий ответ: Да, C осуществляет передачу параметров по ссылке с использованием указателей.
При реализации передачи параметров разработчики языков программирования используют три разные стратегии (или семантические модели): передавать данные в подпрограмму, получать данные из подпрограммы или выполнять обе эти функции. Эти модели обычно известны как в режиме, режиме выхода и режиме выхода, соответственно.
Разработчики языка разработали несколько моделей для реализации этих трех элементарных стратегий передачи параметров:
Pass-by-Value (в семантике режима) Pass-by-Result (семантика режима out) Pass-by-Value-Result (семантика режима inout) Pass-by-Reference (семантика режима inout) Pass-by-Name (входной режим семантика)
Передача по ссылке является вторым методом передачи параметров в режиме ожидания. Вместо копирования данных между основной подпрограммой и подпрограммой назад и вперед система времени выполнения отправляет путь прямого доступа к данным подпрограммы. В этой стратегии подпрограмма имеет прямой доступ к данным, эффективно разделяя данные с основной программой. Основным преимуществом этого метода является то, что он абсолютно эффективен во времени и пространстве, потому что нет необходимости дублировать пространство и нет операций копирования данных.
Реализация передачи параметров в C: C реализует семантику передачи по значению, а также семантику передачи по ссылке (в режиме inout), используя указатели в качестве параметров. Указатель отправляется в подпрограмму, и никакие фактические данные не копируются вообще. Однако, поскольку указатель является путем доступа к данным основной подпрограммы, подпрограмма может изменить данные в основной подпрограмме. C принял этот метод от ALGOL68.
Реализация передачи параметров в C ++: C ++ также реализует семантику передачи по ссылке (inout mode) с использованием указателей, а также с использованием специального вида указателя, называемого ссылочным типом. Указатели на ссылочные типы неявно разыменовываются внутри подпрограммы, но их семантика также передается по ссылке.
Таким образом, ключевая концепция здесь заключается в том, что передача по ссылке реализует путь доступа к данным вместо копирования данных в подпрограмму. Пути доступа к данным могут быть явно разыменованными указателями или автоматически разыменованными указателями (ссылочный тип).
Для получения дополнительной информации, пожалуйста, обратитесь к книге «Концепции языков программирования» Роберта Себесты, 10-е издание, глава 9.
источник
Вы не передаете int по ссылке, вы передаете указатель на an-int по значению. Другой синтаксис, одно и то же значение.
источник
void func(int* ptr){ *ptr=111; int newValue=500; ptr = &newvalue }
сint main(){ int value=0; func(&value); printf("%i\n",value); return 0; }
, он печатает 111 вместо 500. Если вы передаете по ссылке, он должен вывести 500. C не поддерживает передачу параметра по ссылке.ptr = &newvalue
будет запрещено. Независимо от разницы, я думаю, вы указываете, что «одно и то же значение» не совсем верно, потому что у вас также есть дополнительная функциональность в C (возможность переназначения самой «ссылки»).ptr=&newvalue
если это передается по ссылке. Вместо этого мы пишемptr=newvalue
Вот пример на C ++:void func(int& ptr){ ptr=111; int newValue=500; ptr = newValue; }
значение параметра, переданного в func (), станет500
.param = new Class()
внутри функции не будет иметь никакого эффекта для вызывающей стороны, если оно передается по значению (указателю). Еслиparam
передать по ссылке, изменения будут видны для вызывающей стороны.В C для передачи по ссылке вы используете оператор address-of,
&
который следует использовать для переменной, но в вашем случае, поскольку вы использовали переменную-указательp
, вам не нужно ставить перед ней префикс address-of. Было бы справедливо , если вы использовали в&i
качестве параметра:f(&i)
.Вы также можете добавить это к разыменованию
p
и посмотреть, как это значение соответствуетi
:источник
указатели и ссылки - это два разных принципа.
Пара вещей, которые я не видел, упоминается.
Указатель - это адрес чего-либо. Указатель может быть сохранен и скопирован как любая другая переменная. Таким образом, он имеет размер.
Ссылка должна рассматриваться как алиас чего-то. Он не имеет размера и не может быть сохранен. Это ДОЛЖНО ссылаться на что-то, т.е. он не может быть нулевым или измененным. Ну, иногда компилятору нужно хранить ссылку как указатель, но это деталь реализации.
Со ссылками у вас нет проблем с указателями, такими как обработка владения, проверка нуля, снятие ссылок на использование.
источник
«Передача по ссылке» (с помощью указателей) была в C с самого начала. Почему вы думаете, что нет?
источник
j
( не*j
) вf()
не влияет наi
вmain()
.Я думаю, что C на самом деле поддерживает передачу по ссылке.
В большинстве языков синтаксический сахар требуется передавать по ссылке, а не по значению. (Например, C ++ требует & в объявлении параметра).
С также требует синтаксического сахара для этого. Это * в объявлении типа параметра и & в аргументе. Так * и & - это синтаксис языка Си для передачи по ссылке.
Теперь можно утверждать, что для реального прохождения по ссылке требуется только синтаксис в объявлении параметра, а не на стороне аргумента.
Но теперь приходит C # , которая делает поддержку ссылочной мимоходом и требует синтаксический сахар на обоих параметров и аргументов сторон.
Аргумент, что C не имеет передачи by-ref, заставляет синтаксические элементы выражать его, демонстрируя основную техническую реализацию, вообще не является аргументом, поскольку это более или менее применимо ко всем реализациям.
Единственным оставшимся аргументом является то, что передача по ссылке в C не является монолитной функцией, а объединяет две существующие функции. (Возьмите ref аргумента от &, ожидайте, что ref напечатайте *.) Например, C # требует двух синтаксических элементов, но их нельзя использовать друг без друга.
Это, очевидно, опасный аргумент, потому что многие другие функции в языках состоят из других функций. (например, поддержка строк в C ++)
источник
То, что вы делаете, это передача по значению, а не передача по ссылке. Потому что вы отправляете значение переменной 'p' в функцию 'f' (в основном как f (p);)
Та же самая программа на C с передачей по ссылке будет выглядеть так: (!!! эта программа выдает 2 ошибки, так как передача по ссылке не поддерживается в C)
Вывод:-
источник