указатели против ссылок против обычного прохода по значению с ++ - PullRequest
0 голосов
/ 22 февраля 2010

Пожалуйста, прочитайте, прежде чем ответить. Я не хочу, чтобы вы утверждали очевидное для меня. СПАСИБО: D

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

andy = 25;
fred = andy;
ted = &andy; 

В первой строке передается значение 25 для andy. Вторая строка передает значение Энди Фреду. Теперь fred имеет значение 25. Третья строка передает ссылку на ted. Теперь ted содержит адрес памяти andy, который содержит значение 25. Теперь взгляните на следующий код

andy = 25;
fred = andy;
ted = &andy; 
joe = *andy;

Приведенный выше код выглядит так же, как и первый фрагмент, за исключением того, что мы передаем указатель andy для joe. Теперь у joe есть значение указателя 25. Это выглядит почти так же, как просто (joe = andy). без *

в чем разница при передаче значения указателя по сравнению с передачей только по значению ???

В моей интерпретации, кажется, что значение указателя joe все еще затронуто, если позже в строке я решил изменить значение andy / по сравнению с тем, если я только что передал по значению, это не повлияет T

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

Вот ссылка на то, что я читал

http://www.cplusplus.com/doc/tutorial/pointers/

Спасибо, ребята !!!

Ответы [ 5 ]

6 голосов
/ 22 февраля 2010

То, о чем вы говорите, не имеет ничего общего с передачей по ссылке или передачей по значению.Эти термины относятся только к тому, что происходит с параметрами, когда выполняются вызовы функций.Каноническим примером является функция swap().Эта функция:

void swap(int a, int b)
{
    int t = a;
    a = b;
    b = tmp;
}

ничего не делает;параметры не поменяются местами, если вы их вызовите, поскольку они передаются по значению.Если вы делаете их по ссылке (в C ++) или передаете указатели (в C или C ++), он будет делать то, что вы хотите:

void swap(int *a, int *b)
{
    int t = *a;
    *a = *b;
    *b = t;
}

или только в C ++,

void swap(int &a, int &b)
{
    int t = a;
    a = b;
    b = a;
}

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

3 голосов
/ 22 февраля 2010

Вы не можете сделать joe = *andy, потому что Энди не указатель, это int.

Однако вы можете сделать joe = *ted, потому что Тед - это указатель.

Предположим, вы сделали это:

andy = 25; 
fred = andy; 
ted = &andy;  
joe = *ted;
andy = 26;
jim = *ted;

Тогда Джо будет иметь значение 25, а Джим будет иметь значение 26.

Причина этого в том, что Тед является указателем на Энди. Использование *ted дает вам значение по этому указателю в то время.

1 голос
/ 22 февраля 2010

В вашем примере показан пример присваивания и ссылки / разыменования указателя / объекта, а не передачи по значению или ссылке. Как и то, что Саксон сказал выше, вы не можете назначить joe = * andy.

Проще говоря, вы можете определить их как:

  • передача по значению: вы передаете копию значение функции. Копия существовал в рамках только функция Любые изменения в нем есть локально в сферу, например. void funcA (int а)
  • передача по ссылке: вы передаете адрес объекта, который содержит значение, функции, и объект все еще существует в пределах родительской области. У вас есть адрес объекта, который находится в родительской области видимости, поэтому в этот же объект будут внесены изменения. например. пустая забава (int & a)
  • передача по указателю: вы передаете указатель, содержащий адрес этого объекта. Вы фактически передаете указатель как значение (удерживаете адрес объекта) в методе. Если вы измените указатель на другой объект, исходный объект в родительской области не изменится. Если вы хотите изменить объект, на который он указывает, вы должны почтить его. например. void funA (int * a)
1 голос
/ 22 февраля 2010

Я думаю, вы как раз там, но вы путаете терминологию. Давайте снова посмотрим на ваши примеры:

andy = 25;
Фред = Энди;
Тед = & andy;

В первой строке присваивается значение 25 для andy. Во второй строке присваивается значение, которое хранит andy для fred (в данном случае 25). Третья строка назначает адрес Энди Теду.

Все три переменные содержат независимые значения. Изменение любого из них не повлияет на остальные.

Теперь рассмотрим следующий пример:

andy = 25;
Фред = Энди;
ted = & andy;
Джо = * Энди;

Как вы сказали, первые три строки одинаковы. В четвертой строке присваивается значение, на которое указывает andy, joe В этом случае joe теперь будет хранить значение в ячейке памяти 25, потому что andy обрабатывается как ячейка памяти (и в этом случае фактическое значение неизвестно, потому что мы не знаем по данным, что хранится по адресу 25).

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

Итак, давайте посмотрим на другой пример:

andy = 35;
Джим = & Энди; alex = * jim;

В первой строке присваивается значение 25 для andy. Здесь нет ничего нового. Вторая строка назначает адрес Энди Джиму. Третья строка разыменовывает адрес, сохраненный в jim, и присваивает значение alex. Переменная alex теперь содержит значение 25. Но 25, которые содержит alex, отличается от 25, чем то, что держит alan, потому что alan и alex живут по разным адресам памяти. Если мы изменим значение alan на 30, alex все равно будет удерживать 25.

Последний пример:

andy = 25;
jim = & andy;
* джим = 30;

Первые две строки такие же, как в предыдущем примере, andy имеет значение 25, а jim содержит адрес andy.

Третья строка присваивает значение 30 адресу памяти, указанному Джимом. Поскольку это тот же адрес, по которому живет andy, andy теперь имеет значение 30. В этом случае andy и * jim ссылаются на одну и ту же ячейку памяти.

Термины передача по значению и передача по указателю (или передача по ссылке) относятся к передаче параметров в функции. При передаче по значению, например:

void myfunc(int a) { a = a+5; }

А затем вызывается как:

int b = 2;
MyFunc (б);

Значение b по возвращении из функции не изменяется, потому что вы просто передали значение b в функцию, присвоив его a. Переменная a была изменена, но, поскольку она находится по другому адресу памяти, изменение a не повлияло на значение b.

Но при передаче по указателю, как в:

void myfunc(int* a) { *a = *a+5; }

А затем вызывается как:

int b = 2;
MyFunc (& б); * +1070 *

Значение b изменено с 2 на 7, потому что вы передали адрес b в функцию, а затем разыменовали адрес для получения текущего значения getit, добавили 5 к нему и сохранили результат обратно по тому же адресу. Когда функция возвращается, значение, сохраненное по адресу b, обновляется.

0 голосов
/ 22 февраля 2010

В чем смысл передачи по ссылке и передачи по значению?

Вы правы, в этом контексте нет никакой разницы между

(а) непосредственным назначением значений, например(joe = andy) и
(b) Копирование адреса памяти и последующая разыменование, например, (ted = &andy; joe = *ted;)

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

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

Допустим, у вас естьПрограмма, которая отслеживает количество студентов в классе.Когда новый ученик присоединяется к классу, вызывается функция AddStudent для увеличения числа учеников в классе.Здесь есть две версии AddStudent: передача по ссылке и передача по значению.Мы позвоним каждому из main и распечатаем результаты, чтобы увидеть разницу.

int AddStudent_pass_by_value(int value)
{
    value = value+1;
    printf("Number of students (within function): %d\n", value);
    return 0;
}

int AddStudent_pass_by_reference(int* value)
{
    *value = *value+1;
    printf("Number of students (within function): %d\n", *value);
    return 0;
}

int main()
{
    int NumStudents = 0;  //number of students
    printf("Number of students, (within main): %d\n", NumStudents);
    printf("Pass it by value\n");
    AddStudent_pass_by_value(NumStudents);
    printf("Number of students (within main): %d\n\n", NumStudents); 
    /*In main, the value is still 0! The function has not changed the original variable, just a copy of it.*/

    printf("Now pass it by reference\n");
    AddStudent_pass_by_reference(&NumStudents);
    printf("Number of students (within main): %d\n", NumStudents);  
    /*Now, because we passed by reference, the original variable has been changed. */
    return 0;
}

Надеюсь, это поможет ...

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