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

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

17 голосов
/ 17 декабря 2009

Я пытаюсь использовать передачу по ссылке в C, чтобы функция могла изменять значения параметров, передаваемых ей. Это подпись функции:

int locate(char *name, int &s, int &i)

Однако, когда я пытаюсь скомпилировать его, я получаю эту ошибку, которая относится именно к приведенной выше строке:

ошибка: ожидается ‘;’, ‘,’ или ‘) 'до Знак & &

Если я уберу '&', программа скомпилируется, но, очевидно, она не будет работать правильно. Что здесь не так? Как мне сделать звонок по справочной работе?

Ответы [ 7 ]

37 голосов
/ 17 декабря 2009

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

int locate(char *name, int *s, int *i)
{
    /* ... */

    *s = 123;
    *i = 456;
}

int s = 0;
int i = 0;
locate("GMan", &s, &i);

/* s & i have been modified */
20 голосов
/ 17 декабря 2009

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

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

int  locate (char *name,  int  * const s, int * const i)
7 голосов
/ 17 декабря 2009

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

int locate(char *name, int *s, int *i)

и указатели на переменные второго и третьего параметров.

2 голосов
/ 05 июля 2017

Представленные ранее ответы, похоже, не содержат контекста и не учитывают свойство, которое указатели 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 может передавать аргументы по ссылке.

Контексты как определений сигнатур функций, так и вызовов функций изменяют то, как компилятор смотрит на перегрузку указателей по сравнению со ссылками, и как среда выполнения может их реально решать.

1 голос
/ 30 августа 2017

(Я уже некоторое время пользуюсь C, но я все еще плохо знаком с несколькими понятиями в C. Я пытаюсь ответить на это, насколько мне известно, не стесняйтесь исправлять меня, если я ошибаюсь)

Когда вы говорите «передать по ссылке», вы передаете адрес и делаете так, чтобы вы использовали указатели, указывающие на адреса. Таким образом, вам нужно передать указатели на прототип функции, но то, что вы делаете, - это передача адреса напрямую.

Ваша функция пытается отменить ссылку (используя &) на ваш указатель, но у вас никогда не было указателя на параметры 's' и 'i', чтобы отменить ссылку на него.

Правильный способ сделать для прототипа / определения функции -

int locate(char *name, int *s, int *i)

и когда вам нужно вызвать эту функцию, вы используете приведенное ниже объявление в основной или вызывающей функции

int locate(char *name, &s, &i)  
1 голос
/ 04 февраля 2016

Если вы хотите использовать метод передачи по ссылке для изменения параметра, используемого в вызове функции, всегда используйте указатели в качестве формальных аргументов функции.

Следовательно, вместо использования этого

int locate(char *name, int &s, int &i)

использование,

int locate(char *name, int *s, int *i)

Когда вы будете вызывать эту функцию, вы можете использовать

.........

int a=5;
int d=10;
char c='A'; 
int result;

result=locate(&c, &a, &d);

Надеюсь, теперь все станет ясно,

Для получения дополнительной информации о передаче по значению или передаче по ссылке и какой из них лучше, этот источник хорош для начинающих

http://www.learnc.net/call-by-reference.php

Веселитесь.

1 голос
/ 17 декабря 2009

Вы не можете сделать это в c. c не имеет ссылки, вместо этого вы можете использовать указатель.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...