Считаются ли указатели методом вызова по ссылке в C?


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

пример того, что считается "вызовом по ссылочной функции" моим профессором:

int sum(int *a, int *b);

пример того, что считается "вызовом функции значения" моим профессором:

int sum(int a, int b);

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

в основном, это неправильно чтобы сказать, что указатели-это способ передачи C по ссылке? Будет ли это правильно сказать, что вы не можете пройти по ссылке в C, но можете использовать указатели в качестве альтернативы?


обновление 11/11/15

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

  • pass-by-reference (термин, используемый в основном сегодня): the конкретные термин, используемый в таких языках, как C++
  • pass-by-reference (термин, используемый моим профессором в качестве парадигмы для объяснения указателей): the общие термин, используемый до того, как были разработаны такие языки, как C++, и, следовательно, до того, как термин был переписан

после прочтения обновленного ответа @ Haris имеет смысл, почему это не так Черно и белый.

8 65

8 ответов:

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

Да, все правильно.


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

разница заключается в том, что вы отправляете.

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


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

  • если вы не отправляя адрес переменной, тогда также отправляется только значение(адрес в этом случае), но поскольку у вас есть адрес переменной, его можно использовать для изменения исходного значения.


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

// Program to sort two numbers using call by reference. 
// Smallest number is output first.

#include <iostream>
using namespace std;

// Function prototype for call by reference
void swap(float &x, float &y);

int main()
{
   float a, b;

   cout << "Enter 2 numbers: " << endl;
   cin >> a >> b;
   if(a>b) 
     swap(a,b); // This looks just like a call-by-value, but in fact
                // it's a call by reference (because of the "&" in the
                // function prototype

   // Variable a contains value of smallest number
   cout << "Sorted numbers: ";
   cout << a << " " << b << endl;
   return 0;
}

// A function definition for call by reference
// The variables x and y will have their values changed.

void swap(float &x, float &y)
// Swaps x and y data of calling function
{
   float temp;

   temp = x;
   x = y;
   y = temp;
}

в этом примере C++,ссылочной переменной(который отсутствует в C) используется. Цитировать этой сайт,

"ссылка-это псевдоним или альтернативное имя существующей переменной...",

и

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

это отличается от использования указателей в качестве параметров функции, потому что,

"переменная-указатель (или указатель короче) в основном такая же, как и другие переменные, которые могут хранить данные. В отличие от обычной переменной, которая хранит значение (например, int, double, char), указатель хранит адрес памяти."

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


обновление: 11 ноября 2015

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

давайте посмотрим на какой-то простой код C

int i;
int *p = &i;
*p = 123;

в этом сценарии можно использовать терминологию, которая значение p является ссылкой чтобы я. Итак, если это так, то если мы отправим один и тот же указатель (int* p) функции, можно утверждать, что после iС ссылкой отправляется в функцию, и, таким образом, это можно назвать pass-by-reference.

Итак, это вопрос терминологии и способа взглянуть на сценарий.

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


Примечание: обновление вдохновленная этой чат.

Ссылка-это перегруженный термин здесь; в общем, ссылка-это просто способ ссылаться на что-то. Указатель ссылается на объект, на который указывает, и передача (по значению) указателя на объект является стандартным способом передачи по ссылке в C.

C++ ввел ссылочные типы как лучший способ выражения ссылок и вводит двусмысленность в технический английский язык, поскольку теперь мы можем использовать термин "pass by reference" для обозначения использования ссылочных типов для передачи объекта ссылка.

в контексте C++ прежнее использование, IMO, устарело. Однако я считаю, что первое использование распространено в других контекстах (например, чистый C), где нет двусмысленности.

есть ли у C даже "пройти по ссылке"?

не совсем так.

строго говоря, C всегда использует pass by value. Вы можете имитировать проход по ссылке самостоятельно, определяя функции, которые принимают указатели, а затем используя & оператор при вызове, и компилятор будет по существу имитировать его для вас, когда вы передаете массив в функцию (передавая указатель вместо этого, см. вопрос 6.4 и др.).

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

в принципе, C не имеет ничего действительно эквивалентного формальному проходу по ссылке или c++ ссылочных параметров.

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

int main(void)
{
    int num1 = 5;
    int num2 = 10;

    int *pnum1 = &num1;
    int *pnum2 = &num2;
    int ptemp;

    printf("Before swap, *Pnum1 = %d and *pnum2 = %d\n", *pnum1, *pnum2);
    temp = pnum1;
    pnum1 = pnum2;
    pnum2 = ptemp;

    printf("After swap, *Pnum1 = %d and *pnum2 = %d\n", *pnum1, *pnum2);
}

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

void swap(int *pnum1, int *pnum2)
{
     int *ptemp = pnum1;
     pnum1 = pnum2;
     pnum2 = temp;
}

int main(void)
{
    int num1 = 5;
    int num2 = 10;

    int *pnum1 = &num1;
    int *pnum2 = &num2;

    printf("Before swap, *pnum1 = %d and *pnum2 = %d\n", *pnum1, *pnum2);
    swap(pnum1, pnum2);

    printf("After swap, *pnum1 = %d and *pnum2 = %d\n", *pnum1, *pnum2);
}

бум! Никакой подмены!


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

от стандарта C99 (акцент мой):

6.2.5 типы

20 любое количество производных типов может быть построено из типов объектов и функций, как следует:

...

- A указатель на типe может быть производным от типа функции или типа объекта, называемого ссылка типа. тип указателя описывает объект, значение которого содержит ссылку на сущность ссылки типа. Тип указателя, производный от ссылочного типа T, иногда называется " указатель на T’. Построение типа указателя из ссылочного типа называется "производным типа указателя". Тип указателя-это тип объекта.

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

"передача по ссылке" - это понятие. Да, вы передаете значение указателя на функцию, но в этом случае значение этого указателя используется для ссылки на переменную.

кто-то еще использовал аналогию с отверткой, чтобы объяснить, что неправильно ссылаться на прохождение указателей как на прохождение по ссылке, говоря, что вы можете ввернуть винт с монетой, но это не означает, что вы назовете монету отверткой. Я бы сказал, что это отличная аналогия, но они приходят к неверному выводу. На самом деле, хотя вы не утверждаете, что монета была отверткой, вы все равно скажете, что вы завинтили винт с ним. т. е. даже если указатели не совпадают со ссылками на c++, что вы используете их для выполнения - это пройдя по ссылке.

C передает Аргументы по значению, период. Однако указатели являются это может быть использовано для эффективно передача аргументов по ссылке. Так же, как монета может быть использована эффективно в качестве отвертки, если у вас есть правильный вид винта: некоторые винты щели даже выбраны, чтобы хорошо работать с монетами. Они все еще не превращают монеты в настоящие отвертки.

C++ по-прежнему передает Аргументы по значению. Ссылки на C++ гораздо больше ограниченные, чем указатели (хотя и имеющие больше неявных преобразований) и не могут стать частью структур данных, и их использование выглядит намного более похожим на обычный код вызова по ссылке, но их семантика, в то время как очень угодила потребностям параметров вызова по ссылке, все еще более ощутима, чем у чистых реализаций вызова по ссылке, таких как параметры Fortran или Pascal var параметры и вы можете использовать ссылки отлично вне вызова функции контексты.

ваш профессор прав. По значению он копируется. По ссылке, он не копируется, ссылка говорит, где он находится.

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

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

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

в языках, которые поддерживают pass-by-reference, существует средство, с помощью которого функция может быть задана что-то, что может быть использовано для идентификации переменной, известной вызывающему, пока вызываемая функция не вернется,но которые могут храниться только в местах, которые не будут существовать после этого. Следовательно, вызывающий объект может знать, что все, что будет сделано с переменной в результате передачи некоторой функции, ссылка на нее будет выполнена к моменту выполнения функции возвращается.

сравните программы C и C#:

// C               // C#
int x=0;           int x=0;
foo(&x);           foo(ref x);
x++;               x++;
bar();             bar();
x++;               x++;
boz(x);            boz(x);

компилятор C не может знать, может ли" бар " изменить x, потому что foo () получил неограниченный указатель на него. Напротив, компилятор C# знает, что bar () не может изменить x, так как foo () получает только a временная ссылка (называемая "byref" в терминологии .NET) на него и там не может ли какая-либо копия этого byref выжить после точки, где foo() возвращается.

при передаче указателей чтобы вещи позволяли коду do то же самое, что можно сделать с семантикой pass-by-ref, но семантика pass-by-ref позволяет коду предлагать более сильные гарантии о вещах, которые он не сделать.