Подтвердить что ты не робот

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

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

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

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

Пример того, что мой профессор говорит "вызов по значению":

int sum(int a, int b);

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

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


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

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

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

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

4b9b3361

Ответ 1

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

Yup, thats correct.


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

Что отличает то, что вы отправляете.

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


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

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


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

// 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 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). Чтобы процитировать этот веб-сайт,

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

и

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

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

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

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


ОБНОВЛЕНИЕ: 11 ноября 2015 г.

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

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

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

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

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

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


ПРИМЕЧАНИЕ. Обновление, вдохновленное этим чатом.

Ответ 2

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

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

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

Ответ 3

Из стандарта C99 (ударный удар):

6.2.5 Типы

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

...

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

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

Ответ 4

Есть ли у C` `pass by reference ''?

Не совсем.

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

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

В принципе, 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);
}

Boom! Без обмена!


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

Ответ 5

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

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

Ответ 6

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

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

Ответ 7

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

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

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

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

Ответ 8

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

Сравните программы 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() получил неограниченный указатель на него. Напротив, компилятор С# знает, что bar() не может изменить x, так как foo() получает только временную ссылку (называемую "byref" в терминологии .NET) к ней и там не является никаким способом для любой копии этого byref, чтобы выжить за точку, где foo() возвращается.

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