Передача по ссылке в C

Если 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 

Ответ 1

Поскольку вы передаете значение указателя на этот метод и затем разыгрываете его, чтобы получить целое число, на которое указывает.

Ответ 2

Это не перекрестная ссылка, это пропускная способность, как указано другими.

Язык C - это без исключения пробел. Передача указателя как параметр не означает "прохождение по ссылке".

Правило следующее:

Функция не может изменить значение фактических параметров.


Попробуйте увидеть различия между скалярными и указательными параметрами функции.

Скалярные переменные

Эта короткая программа показывает значение pass-by-value с использованием скалярной переменной. param называется формальным параметром, а variable при вызове функции называется фактическим параметром. Примечание. Приращение param в функции не изменяется variable.

#include <stdio.h>

void function(int param) {
    printf("I've received value %d\n", param);
    param++;
}

int main(void) {
    int variable = 111;

    function(variable);
    printf("variable %d\m", variable);
    return 0;
}

Результат

I've received value 111
variable=111

Иллюзия передачи по ссылке

Мы немного изменим часть кода. param теперь является указателем.

#include <stdio.h>

void function2(int *param) {
    printf("I've received value %d\n", *param);
    (*param)++;
}

int main(void) {
    int variable = 111;

    function2(&variable);
    printf("variable %d\n", variable);
    return 0;
}

Результат

I've received value 111
variable=112

Это заставляет вас поверить, что параметр был передан по ссылке. Не было. Он был передан по значению, а значение параметра - адресом. Значение типа int было увеличено, и это побочный эффект, который заставляет нас думать, что это вызов функции передачи по ссылке.

Указатели - пройдены по значению

Как мы можем показать/доказать этот факт? Ну, может быть, мы можем попробовать первый пример переменных Scalar, но вместо скалярного мы используем адреса (указатели). Посмотрите, поможет ли это.

#include <stdio.h>

void function2(int *param) {
    printf("param address %d\n", param);
    param = NULL;
}

int main(void) {
    int variable = 111;
    int *ptr = &variable;

    function2(ptr);
    printf("ptr address %d\n", ptr);
    return 0;
}

Результат будет таким, что два адреса равны (не беспокойтесь о точном значении).

Результат:

param address -1846583468
ptr address -1846583468

По-моему, это ясно показывает, что указатели передаются по значению. В противном случае ptr будет NULL после вызова функции.

Ответ 3

В C моделируется сквозная ссылка путем передачи адреса переменной (указатель) и разыменование адрес внутри функции для чтения или напишите фактическую переменную. Это будет называться "Стиль C" пройти по ссылке ".

Источник: www-cs-students.stanford.edu

Ответ 4

Потому что в приведенном выше коде отсутствует пропускная ссылка. Использование указателей (например, void func(int* p)) является сквозным адресом. Это передача по ссылке в С++ (не будет работать в C):

void func(int& ref) {ref = 4;}

...
int a;
func(a);
// a is 4 now

Ответ 5

Ваш пример работает, потому что вы передаете адрес своей переменной функции, которая управляет ее значением с помощью оператора разыменования.

В то время как C не поддерживает ссылочные типы данных, вы все же можете моделировать передачу по ссылке, явно передавая значения указателя, как в вашем примере.

Тип ссылочных данных С++ менее мощный, но считается более безопасным, чем тип указателя, унаследованный от C. Это будет ваш пример, адаптированный для использования ссылок С++:

void f(int &j) {
  j++;
}

int main() {
  int i = 20;
  f(i);
  printf("i = %d\n", i);

  return 0;
}

Ответ 6

Вы передаете указатель (расположение адреса) по значению.

Мне нравится говорить "здесь место с данными, которые я хочу вам обновить".

Ответ 7

p - указательная переменная. Его значение - адрес i. Когда вы вызываете f, вы передаете значение p, которое является адресом i.

Ответ 8

Нет пропусков в C, но p "ссылается" на i, и вы передаете p по значению.

Ответ 9

В C все передается по значению. Использование указателей дает нам иллюзию того, что мы передаем ссылку, потому что изменяется значение переменной. Однако, если вы хотите распечатать адрес переменной указателя, вы увидите, что это не влияет. копия значения адреса передается функции. Ниже приведен фрагмент, иллюстрирующий это.

void add_number(int *a) {
    *a = *a + 2;
}

int main(int argc, char *argv[]) {
   int a = 2;

   printf("before pass by reference, a == %i\n", a);
   add_number(&a);
   printf("after  pass by reference, a == %i\n", a);

   printf("before pass by reference, a == %p\n", &a);
   add_number(&a);
   printf("after  pass by reference, a == %p\n", &a);

}

before pass by reference, a == 2
after  pass by reference, a == 4
before pass by reference, a == 0x7fff5cf417ec
after  pass by reference, a == 0x7fff5cf417ec

Ответ 10

Потому что вы передаете указатель (адрес памяти) переменной p в функцию f. Другими словами, вы передаете указатель, а не ссылку.

Ответ 11

Короткий ответ: Да, C реализует передачу параметров по ссылке с помощью указателей.

При реализации передачи параметров разработчики языков программирования используют три разные стратегии (или семантические модели): переносят данные в подпрограмму, получают данные из подпрограммы или выполняют оба. Эти модели обычно известны как в режиме, в режиме выхода и в неактивном режиме соответственно.

Несколько моделей были разработаны разработчиками языка для реализации этих трех стратегий управления элементарными параметрами:

Передача по значению (в семантике режима) Передача по результату (семантика режима вывода) Pass-by-Value-Result (inout mode semantics) Pass-by-Reference (семантика inout) Pass-by-Name (семантика inout mode)

Передача по ссылке - это второй метод передачи параметров inout-mode. Вместо копирования данных назад и вперед между основной подпрограммой и подпрограммой система времени выполнения отправляет путь прямого доступа к данным для подпрограммы. В этой стратегии подпрограмма имеет прямой доступ к данным, эффективно разделяющим данные с основной программой. Основное преимущество этого метода заключается в том, что он абсолютно эффективен во времени и пространстве, потому что нет необходимости дублировать пространство и нет операций копирования данных.

Передача параметров в C: C реализует pass-by-value, а также pass-by-reference (inout mode) семантику с использованием указателей в качестве параметров. Указатель отправляется в подпрограмму, и никакие фактические данные не копируются вообще. Однако, поскольку указатель представляет собой путь доступа к данным основной подпрограммы, подпрограмма может изменить данные в основной подпрограмме. C принял этот метод от ALGOL68.

Передача параметров в С++: С++ также реализует семантику pass-by-reference (inout mode) с помощью указателей, а также использует специальный тип указателя, называемый ссылочным типом. Указатели ссылочного типа неявно разыменовываются внутри подпрограммы, но их семантика также является передачей по ссылке.

Итак, ключевая концепция здесь заключается в том, что pass-by-reference реализует путь доступа к данным вместо копирования данных в подпрограмму. Пути доступа к данным могут быть явно разыменованными указателями или указателями автоматической разыменования (ссылочный тип).

Для получения дополнительной информации см. книгу "Концепции языков программирования" Роберта Себеста, 10-е изд., глава 9.

Ответ 12

Вы не передаете int по ссылке, вы передаете указатель-на-int по значению. Различный синтаксис, то же значение.

Ответ 13

В C для передачи по ссылке вы используете адрес-оператора &, который должен использоваться против переменной, но в вашем случае, поскольку вы использовали указательную переменную p, вам не нужно префикс это с адресом оператора. Это было бы верно, если бы вы использовали &i в качестве параметра: f(&i).

Вы также можете добавить это, к разыменованию p и посмотреть, как это значение соответствует i:

printf("p=%d \n",*p);

Ответ 14

указатели и ссылки являются двумя разными тиггами.

Несколько вещей, о которых я не упоминал.

Указатель - это адрес чего-то. Указатель может быть сохранен и скопирован как любая другая переменная. Таким образом, он имеет размер.

Ссылка должна рассматриваться как ALIAS. Он не имеет размера и не может быть сохранен. Он ДОЛЖЕН указать что-то, т.е. он не может быть нулевым или измененным. Ну, иногда компилятор должен хранить ссылку как указатель, но это детализация реализации.

В ссылках у вас нет проблем с указателями, например, с обработкой прав собственности, нулевой проверкой, де-ссылкой на использование.

Ответ 15

"Передать по ссылке" (с помощью указателей) с самого начала был в C. Почему вы думаете, что это не так?

Ответ 16

Я думаю, что C фактически поддерживает передачу по ссылке.

В большинстве языков требуется, чтобы синтаксический сахар передавался по ссылке вместо значения. (Например, требуется С++ и в объявлении параметра).

C также требует для этого синтаксического сахара. Он * в объявлении типа параметра и в аргументе. Таким образом, * и и является синтаксисом C для передачи по ссылке.

Теперь можно утверждать, что для реального прохода по ссылке требуется только синтаксис объявления параметра, а не аргументации.

Но теперь идет С#, который поддерживает передачу ссылок и требует синтаксического сахара как для сторон, так и для аргументов.

Аргумент о том, что C не имеет байтов-ссылок, заставляет синтаксические элементы выражать его, показывает, что базовая техническая реализация не является аргументом вообще, поскольку это более или менее применимо ко всем реализациям.

Единственным оставшимся аргументом является то, что передача ref в C не является монолитной, но сочетает в себе две существующие функции. (Возьмем аргумент аргумента by &, предположим, что ref набирает by *.) Например, для С# требуется два синтаксических элемента, но они не могут использоваться без друг друга.

Это, очевидно, опасный аргумент, потому что многие другие функции на языках состоят из других функций. (например, поддержка строки в С++)

Ответ 17

То, что вы делаете, - это пропуск по значению, не проходящий по ссылке. Поскольку вы отправляете значение переменной 'p' в функцию 'f' (в основном как f (p);)

Такая же программа в C с передачей по ссылке будет выглядеть так: (!!! эта программа дает 2 ошибки, так как передача по ссылке не поддерживается в C)

#include <stdio.h>

void f(int &j) {    //j is reference variable to i same as int &j = i
  j++;
}

int main() {
  int i = 20;
  f(i);
  printf("i = %d\n", i);

  return 0;
}

Вывод: -

3:12: error: expected ';', ',' or ')' before '&' token
             void f(int &j);
                        ^
9:3:  warning: implicit declaration of function 'f'
               f(a);
               ^