Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > В чем отличия указателя от ссылки?


Автор: Wowa 13.1.2005, 03:25
В чем отличия указателя от ссылки?
Добавлено @ 03:27
приведите, пожалуйста, пример указателя и ссылки.

Автор: chipset 13.1.2005, 03:29
Через указатель к примеру передаются массивы.... Через передачу переменной по ссылке так сделать нельзя.

Автор: Guest 13.1.2005, 09:52
Код

//Указатель
int *ptr = new int;
*ptr = 5; //Разименование указателя
cout << *ptr; //Вывести значение
cout << *ptr; //Вывести адрес


Ссылку можно назвать автоматически разименованным указателем..
Код

int t = 7;
int& k = t;
++k;
cout << t; //Напечатает 8


Ссылки можно использовать например так
Код

void function( const string& t ) //Здесь при передаче обьекта типа стринг функции копия не создается (економия памяти однако)
{

}



Автор: azesmcar 13.1.2005, 09:54
извиняюсь, здесь маленькая ошибка

Код

//Указатель
int *ptr = new int;
*ptr = 5; //Разименование указателя
cout << *ptr; //Вывести значение
cout << ptr; //Вывести адрес
delete ptr;

Добавлено @ 09:58
Если убрать const в примере
Код

void function( const string& t ) //Здесь при передаче обьекта типа стринг функции копия не создается (економия памяти однако)
{

}

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

Тут еще кучу примеров можно привести...

Автор: bel_nikita 13.1.2005, 10:14
Ссылка - это ссылка smile Т.е. она ссылается на объект в памяти. Т.е. определяя ссылку, необходимо с помощью начального значения определить тот объект(участок памяти), на который указывает ссылка. Функционально ссылка ведет себя подобно обычной переменной того же типа. Для доступа к содержимому участка памяти, на который "смотрит" ссылка, нет необходимости явно выполнять разыменование, как это нужно для указателя.
Код

int L = 777; // Определена и инициализирована переменная L
int& RL = L; // Значение ссылки RL является адрес переменной L
int *ptr = &L; // указатель на объект L типа int

Например:
Код
RL -= 77;
уменьшает на 77 значение переменной L.
Связав ссылку RL с переменной L, получаем возможность изменять значение переммой двумя способами:
Код
RL = 123;
L = 123;

Также через указатель:
Код
*ptr = 456;

Автор: sergejzr 13.1.2005, 19:48
A теперь внимамие, правильный ответ: smile smile smile

Грубо говоря это - одно и тоже. Ссылка - замаскированный указатель.

Вот так мы работаем с указателем:
Код А:
Код

void set( int *func_n)// в переменную  func_n скопируется значение с которым мы функцию вызвали
{
* func_n=3; //изменение содержмого естественно меняет значение нашей n из main'a
}
int main()
{
int n=3;
int * pointer_n=&n;//теперь pointer_n показывает на n. Изменение содержимого будет менять значение n.
* pointer_n=4; // Вот так. Теперь n у нас стала 4.

set(pointer_n);//передаём в функцию указатель на n.
cout<<n<<endl;//теперь n опять 3.
n=4;
set(&n);// по существу тут то же самое. Только здесь компилер для нас создаст указатель
cout<<n<<endl; //теперь n опять 3.
return 0;
}


А что со сылками?
Код В:
Код

void set( int &reference_n){
reference_n=3;
}
int main(){
int n=3;
int &reference_n=n;
reference_n=4;

set(reference_n);
cout<<n<<endl;
n=4;
set(n);
cout<<n<<endl;
return 0;
}

да тоже самое, эти два кода эквивалентны. (в комментарах из A замените указатель на ссылку)
Компилер сделает из кода B код A. строка в строку.

Так зачем эта неразбериха, которая из года в год путает студентов, спросите вы?
Единственный ответ в красоте кода. Кто когда нибуть писал на Си с применение множества указателей, поймёт.
Эти вечные (&n), *n=6, итд. Просто вырубают наповал. Если давать переменным короткие названия, то весь код будет из звездей и & состоять. smile smile smile

Надеюсь, смог помочь разобраться smile

Автор: DENNN 13.1.2005, 19:56
Цитата
Единственный ответ в красоте кода.

вот и нетsmile
К примеру если в функцию в качестве параметров передаются ссылки, то это дает дополнительную гарантию, что в при вызове этой функции будут переданны реальные значения, а не указатели "в никуда". Отсюда, в частности следует, что такой способ передачи параметров избавляет нас от проверки указателей на "валидность". Отсюда также следует, что при необходимости передачи в функцию массива неизвестной на этапе компиляции длины указатель может быть более удобен, чем использование ссылки.
Добавлено @ 19:58
Цитата
Эти вечные (&n), *n=6, итд. Просто вырубают наповал.

Ну это уж вообще абсолютно субъективное мнение. Я например предпочитаю смотреть в код и видеть, какие же операции выполнит процессор в каждой строчке.

Автор: sergejzr 13.1.2005, 20:04
Цитата(DENNN @ 13.1.2005, 18:56)
К примеру если в функцию в качестве параметров передаются ссылки, то это дает дополнительную гарантию, что в при вызове этой функции будут переданны реальные значения, а не указатели "в никуда". Отсюда, в частности следует, что такой способ передачи параметров избавляет нас от проверки указателей на "валидность". Отсюда также следует, что при необходимости передачи в функцию массива неизвестной на этапе компиляции длины указатель может быть более удобен, чем использование ссылки.

а так?

Код
int &reference;
set(reference);

Цитата(DENNN @ 13.1.2005, 18:56)
Ну это уж вообще абсолютно субъективное мнение. Я например предпочитаю смотреть в код и видеть, какие же операции выполнит процессор в каждой строчке.

Да я тоже smile когда в свой. А вот чужой код намного читабельней становится(если автор придерживался правила не изменять значение аргументов в функциях).

Автор: Fantasist 13.1.2005, 20:44
Цитата(sergej @ 13.1.2005, 17:04)
а так?

int &reference;
set(reference);



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

Код

std::string& get_str()
{
  std::string new_string;

   ............ делаем новую строку.....

   return new_string;    
}  


С точки зрения синтаксиса все правильно, однако объект new_string будет удален при выходе из функции и ссылка будет возвращена невалидная. Хороший компилятор в этом месте выдает предупреждение, что возращается ссылка на стековый объект. Тем не менее, случай может оказатся более замаскированным, так что компилятор его не заметит:

Код

string& get_str()
{
  auto_ptr<string> new_string=new string();

   ............ делаем новую строку.....

   return *new_string;    
}  


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


Добавлено @ 20:48
Цитата(sergej @ 13.1.2005, 17:04)
(если автор придерживался правила не изменять значение аргументов в функциях)


В таком случае это должно быть явно указанно модификатором const для параметра функции. Язык С++ весьма гибок, чтобы большинство правил можно было бы выразить средствоми языка, а не на бумаге или в голове.

Автор: sergejzr 13.1.2005, 21:08
Цитата(Fantasist @ 13.1.2005, 19:44)
Ссылка должны быть инициализированна в месте ее объявления, за исключением того случая, когда ссылка является полем класса - в этом случае она должна быть инициализированна в списки инициализации конструктора.

Ага! Точно smile Это подстраховка компилятора. Сорри, не подумал. Хотя встречались компилеры, которые разрешали, но это нестандартные конечно, а "рукописные" smile
Но всмысле обьяснения отличия указателя от ссылки это всё равно smile Если предварительные проверки ОК, код В переводится в код А.
Цитата(Fantasist @ 13.1.2005, 19:44)
В таком случае это должно быть явно указанно модификатором const для параметра функции.

Ну да smile Ho это ведь к красоте кода отношения не имеет smile. Красота имхо именно из за отсутсвия "лишних" *&.

Автор: Fantasist 13.1.2005, 21:26
Цитата(sergej @ 13.1.2005, 18:08)
Это подстраховка компилятора.


Это не подстраховка а принцип понятия ссылки. Обрати внимание на выделенную мной фразу - если ты ссылку не инициализируешь сразу у тебя не будет возможности сделать это потом.


Автор: DENNN 14.1.2005, 10:48
Цитата
Ну да  Ho это ведь к красоте кода отношения не имеет . Красота имхо именно из за отсутсвия "лишних" *&.

Я минуту улыбался smile

Цитата
Но всмысле обьяснения отличия указателя от ссылки это всё равно

Как же это "все равно"?

Цитата
Цитата (DENNN @ 13.1.2005, 18:56)
Ну это уж вообще абсолютно субъективное мнение. Я например предпочитаю смотреть в код и видеть, какие же операции выполнит процессор в каждой строчке.

Да я тоже когда в свой. А вот чужой код намного читабельней становится(если автор придерживался правила не изменять значение аргументов в функциях).

Давайте все же проясним это туманное понятие "код становится читабельней". А то сейчас это философские рассуждения. Вот ты несколькими постами выше сказал:
Цитата
Эти вечные (&n), *n=6, итд. Просто вырубают наповал.

А я например невижу ничего особенного как в опреаци доступа по указателю, так и в операции взятия адреса. Такая же операция, как к примеру + - %

Автор: Tripl-X 24.1.2005, 23:52
'&' - получение адреса памяти, по которому находится переменная, а '*' - получение значения из адреса.

Вот тебе пример:

Код

int main(void)
{
int target, source;
int *m;

source=10;
m=&source;
target=*m;
printf("[%i][%i]", m, target);

return 0;


Это выведет на экран два разных числа...
Вобщем, если тебе нужно использовать значения переменной - используй *, а если адрес переменной - &.

Автор: PashaLost 29.10.2011, 15:29
По-моему мнению, ветка не содержит ИСЧЕРПЫВАЮЩЕГО ответа на поставленный вопрос. И поэтому: 

УКАЗАТЕЛЬ - это АДРЕС переменной в чистом виде (00 12 FF 60) 
ССЫЛКА - это НЕИЗМЕННЫЙ скрытый указатель, являющийся ещё одним именем для переменной. 

В отличие от указателя, независимые ссылки ДОЛЖНЫ быть инициализированы. 
   Type &ID_ссылки=ID_объекта;

Ссылка должна быть явно инициализирована при её описании (если только она не является параметром функции (в этом случае инициализация произойдёт при замене формальных параметров фактическими) или не описана как extern - в этом случае она будет инициализирована в другом месте)

В отличие от указателя, мы не можем изменять значение ссылки (значение скрытого адреса). 

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

Не существует указателей на ссылки (но существуют указатели на указатели), 
Не существует массивов ссылок (но существуют массивы указателей)
Не существует ссылок на ссылки

Функция не может быть перегружена, если описание её параметров отличается только наличием ссылки ( fun(int a), fun(int &a) )

Преимущества ссылок: 
  Не нужно работать с адресом переменной, он подразумевается автоматически
  Со ссылками работаем как с переменной (а не как с адресом переменной)
  Копия объекта не передаётся в функцию (при передаче параметров функции), а только скрытый адрес.

Автор: borisbn 29.10.2011, 17:35
Цитата(PashaLost @  29.10.2011,  15:29 Найти цитируемый пост)
Преимущества ссылок: 

Сказал "А"...

Недостатки ссылок:
  • Если в ф-цию нужно передать объект по ссылке, а он по каким-либо причинам не может быть создан, но в случае с указателем принято передавать NULL (или 0 или nullptr). В случае со ссылкой такого сделать нельзя
  • Невозможно сделать вектор ссылок (без доп.обёрток). Вектор же указателей - самое обычное дело

Частая ошибка при использовании ссылок:
Код
A objA;
A objB;
A & refA = objA;
...
refA = objB;

В последней строке refA не начинает ссылаться на objB, а objB копируется в objA, как-будто мы написали objA = objB;

Я для себя установил одно простое правило: использовать указатели только в случае, когда использовать ссылки невозможно.
Есть, правда, одно исключение - const char * - да и то, если в заголовочном файле ещё не включен <string> smile

Автор: mes 29.10.2011, 18:30
Цитата(borisbn @  29.10.2011,  16:35 Найти цитируемый пост)
Сказал "А"...

Сказал "Б"...
ссылки в С++ не просто синтаксический сахар для всегда_инициализированного_указателя, но также могут создать поведение которое нельзя получить с помощью указателя..  (и это еще не вспоминая C++11)  smile 

Автор: alexvs11 31.10.2011, 00:22
Цитата(DENNN @  13.1.2005,  19:56 Найти цитируемый пост)
К примеру если в функцию в качестве параметров передаются ссылки, то это дает дополнительную гарантию, что в при вызове этой функции будут переданны реальные значения, а не указатели "в никуда". Отсюда, в частности следует, что такой способ передачи параметров избавляет нас от проверки указателей на "валидность". 

Код

int f(int& val)
{
  return 0;
}

int main()
{
   int* pval = (int*)0x12345;
   f ((int&)*pval);
}

c++ с вами не согласен

Автор: math64 31.10.2011, 07:49
alexvs11, Невалидную ссылку можно получить проще, без таких ухищрений
Код

void f(int& ref);
int array[10];
f (array[10]);

Автор: mes 31.10.2011, 09:13
alexvs11, гарантия не на инвалидность (которая лежит в обоих случаях на плечах вызывающей стороны), а "не_нуль" гарантия..

Добавлено через 1 минуту и 47 секунд
нуль значение для  ссылки не валидно, в отличие от для указателя..

Автор: borisbn 31.10.2011, 15:35
Цитата(mes @  29.10.2011,  18:30 Найти цитируемый пост)
создать поведение которое нельзя получить с помощью указателя

Не понял. Что Вы имели в виду ?

Автор: mes 31.10.2011, 19:06
Цитата(borisbn @  31.10.2011,  14:35 Найти цитируемый пост)
Не понял. Что Вы имели в виду ? 

продлевание жизни rvalue при пристыковании к константной ссылке со всеми вытекающими преимуществами и недостатками..

Автор: borisbn 31.10.2011, 19:19
mes, && ?
Я имею ввиду: Вы имели в виду move semantics ?

Автор: mes 31.10.2011, 20:22
нет.. 
Цитата(mes @  29.10.2011,  17:30 Найти цитируемый пост)
 не вспоминая C++11

говорил всего лишь о const&
smile


Автор: volatile 31.10.2011, 23:45
Если сильно руки чешутся, можно и нулевую ссылку получить  smile 
Код

void f(int & ref);

int main()
{
   f(*(int*)0);
}


http://liveworkspace.org/code/2f66addfa35846cc42b1b2d4719dbd3f

Автор: math64 1.11.2011, 07:48
Цитата(volatile @  31.10.2011,  23:45 Найти цитируемый пост)
Если сильно руки чешутся, можно и нулевую ссылку получить  smile 

Это с ухищрениями. Можно получить ненамеренно:
Код

void f(int & ref);
int main()
{
   int* p = NULL;
   f(*p);
}


Автор: azesmcar 1.11.2011, 09:41
Цитата(volatile @  31.10.2011,  23:45 Найти цитируемый пост)
Если сильно руки чешутся, можно и нулевую ссылку получить   

Нельзя, разыменование нулевого указателя - undefined behavior.
Цитата

A reference shall be initialized to refer to a valid object or function.
[Note: in particular, a null reference cannot exist in a well-defined program, because the only way to create such a reference would be to bind it to the “object” obtained by dereferencing a null pointer, which causes undefined behavior. As described in 9.6, a reference cannot be bound directly to a bit-field.]

Автор: alexvs11 1.11.2011, 09:46
azesmcar, кто спорит
тут вопрос в том, что с++ позволяет все свои правила обходить - в том числе и с нулевой ссылкой

Автор: mes 1.11.2011, 10:29
Цитата(alexvs11 @  1.11.2011,  08:46 Найти цитируемый пост)
 кто спорит
тут вопрос в том, что с++ позволяет все свои правила обходить - в том числе и с нулевой ссылкой 

но не учитываете, что этот обход не нарушает гарантий языка smile

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)