ссылки и указатели в c чем отличаются
Чем отличаются ссылки от указателей в С++
В чем принципиальное отличие ссылки от указателя в С++? Когда лучше использовать ссылку, а когда указатель? Какие ограничения есть у первых, а какие у вторых?
2 ответа 2
Еще отличия:
Указатель может иметь «невалидное» значение с которым его можно сравнить перед использованием.
Если вызывающая сторона не может не передать ссылку, то указатель может иметь специальное значение nullptr :
(Standart) A null pointer constant is an integer literal (2.13.2) with value zero or a prvalue of type std::nullptr_t. A null pointer constant can be converted to a pointer type; the result is the null pointer value of that type and is distinguishable from every other value of object pointer or function pointer type.
Ссылка не обладает квалификатором const
О весёлом
Некоторые ссылаются на отрывок с интервью с Страуструпом:
Очевидной реализацией ссылки является (константный) указатель, при каждом использовании которого происходит разыменование. В некоторых случаях компилятор может оптимизировать ссылку таким образом, что во время исполнения вообще не будет существовать объекта, представляющего ссылку.
Другие задают в ответ лишь в один вопрос:
Чем является реультат разыменовывания указателя?
На тему, нужно ли знать отличия указателя от ссылки, писал Джоэл Спольски в своей статье «Закон Дырявых Абстракций».
Чем различаются указатели в Си от ссылок в C#?
Верно ли, что указатели в Си аналогичны ссылочным типам в C#?
3 ответа 3
Кроме того, указатели С «статичны», а объект в дотнете может быть перемещен сборщиком мусора, т.е. ссылки изменяют свое значение.
В C# также существуют указатели. Они эквивалентны указателям в С.
Позвольте я на простом примере объясню слова andreycha:
Допустим, имеется человек по имени Василий Пупкин, проживающий по адресу Ленина, 1. Его адрес является указателем. А понятие «дом Васи» является ссылкой. Можно сказать: «Едем на вечеринку в доме Васи», без точного указания адреса.
Если Василий теперь переедет на улицу Леннона, 2, то адрес изменится и, соответственно, должен изменится указатель. Меж тем ссылка «дом Васи» останется по-прежнему валидной.
Хотел было докоментировать ответ andreycha, но потом подумал что лучше запостить отдельный ответ.
Начнем с того что понятием указателя(pointer) в С/С++ является адрес обьекта в оперативной памяти и представляет собой следующий синтаксис:
то есть перед названием стоит звездочка.
Так же есть ссылка (reference)
Ссылки — это +- то же самое, что и указатели, но с другим синтаксисом и некоторыми другими важными отличиями. Они там работают вместе и дополняют друг друга: через указатель можно узнать значение по ссылке в С/С++.
пример использования ref в шарпе:
А во всем остальном я согласен с ответом andreycha и дополнением VladDа. То есть:
Указатели и ссылки [дубликат]
Почему при условиях
P.S. Уточняю, прочитав все выше, я понял где то так:
5 ответов 5
Что-то Вы, видимо, не то читали… Обычно в книжках крайне понятно излагают…
Так вот, указатель — это, тупо, то самое число, тот самый адрес. Т.е. &a равно именно в точности адресу в памяти, по которому хранится значение. Чтобы избежать невнятных проблем, тип «указатель на int (или на любой другой тип) — int*» — это такой совершенно отдельный тип.
Про ссылки чуть попозже напишу. Или кто-нибудь другой напишет…
Ссылки же, в свою очередь, обладают не семантикой «адресов объектов», а семантикой самих объектов. Можно думать, что ссылка — это указатель, который сам, автоматически, применяет dereference. Из этого есть несколько следствий: например, неизменяемость ссылок. В C++ просто нет синтакисиса присвоения ссылки, любое такое присвоение будет присвоением объекту, на который она указывает.
Если говорить о глубоких мыслях, то, прежде всего, указатели пришли из C и остались тяжёлым наследием. Думаю, некорректная адресация к памяти — самая частая причина падения программ на C++. Ссылки заменить указатели не могут (они не объекты, в отличие от указателей), но здорово упрощают жизнь, когда вам надо передать некоторую структуру весом в пару килобайт параметром в функцию, и копирование замедлит выполнение программы, но Вы не хотите руками возится с указателями. Ссылки имеют такой же синтаксис использования, как и объекты, на которые они ссылаются, и поэтому более-менее взаимозаменяемы.
Чувствую, что написал-то я уже много, а ничего ясного сформулировать не смог 🙁
Надеюсь, хоть немного понятнее стало
Указатели и ссылки: в чем разница
Указатели и ссылки: в чём их разница и сходство?
Я начал учить с++ и не могу кое в чём разобраться. Кто знает ответы на эти вопросы может ответить.
в чем разница? массивы и указатели строк
В примере Дейтла ( в документе ) массивы строк инициализируются через указатели, при этом.
Ещё важно понимать что ссылка и указатель это не совсем одно и то же.
Например для ссылок нет адресной арифметики, а у указателей есть.
С помощью ссылок так же можно безопасно ссылаться на временные объекты (константные ссылки, либо rvalue ссылки, если требуется модифицировать временный объект).
Так же ссылки требуют того, что бы определение было сразу при объявлении, а указатели этого не требуют.
Может под капотом эти ссылки и реализованы как указатель, но с точки зрения компилятора в коде программиста это не одно и то же.
А ещё есть такое понятие как ссылка на указатель)))
На самом деле странная у Вас формулировка) Вот эта часть мне не очень понятна:
Renji, я неправильно Вас понял, извиняюсь. Перелили с пустого в порожнее.
А вернее совсем не одно и то же.
Начать можно с того, что указатель является объектом, а ссылка — нет. И этим они различаются фундаментально.
Ссылка занимает определенный объем памяти. Никакой другой объект не может занимать этот объем одновременно с ней. В этом смысле она объект. Ну а что касается того что компилятор не дает непосредственно пронаблюдать этот объем через sizeof или оператор взятия адреса:
Указатели, ссылки и массивы в C и C++: точки над i
В этом посте я постараюсь окончательно разобрать такие тонкие понятия в C и C++, как указатели, ссылки и массивы. В частности, я отвечу на вопрос, так являются массивы C указателями или нет.
Обозначения и предположения
Указатели и ссылки
Указатели. Что такое указатели, я рассказывать не буду. 🙂 Будем считать, что вы это знаете. Напомню лишь следующие вещи (все примеры кода предполагаются находящимися внутри какой-нибудь функции, например, main):
Ссылки. Теперь по поводу ссылок. Ссылки — это то же самое, что и указатели, но с другим синтаксисом и некоторыми другими важными отличиями, о которых речь пойдёт дальше. Следующий код ничем не отличается от предыдущего, за исключением того, что в нём фигурируют ссылки вместо указателей:
Если слева от знака присваивания стоит ссылка, то нет никакого способа понять, хотим мы присвоить самой ссылке или объекту, на который она ссылается. Поэтому такое присваивание всегда присваивает объекту, а не ссылке. Но это не относится к инициализации ссылки: инициализируется, разумеется, сама ссылка. Поэтому после инициализации ссылки нет никакого способа изменить её саму, т. е. ссылка всегда постоянна (но не её объект).
Удивительный факт состоит в том, что ссылки и lvalue — это в каком-то смысле одно и то же. Давайте порассуждаем. Что такое lvalue? Это нечто, чему можно присвоить. Т. е. это некое фиксированное место в памяти, куда можно что-то положить. Т. е. адрес. Т. е. указатель или ссылка (как мы уже знаем, указатели и ссылки — это два синтаксически разных способа в C++ выразить понятие адреса). Причём скорее ссылка, чем указатель, т. к. ссылку можно поместить слева от знака равенства и это будет означать присваивание объекту, на который указывает ссылка. Значит, lvalue — это ссылка.
А что такое ссылка? Это один из синтаксисов для адреса, т. е., опять-таки, чего-то, куда можно класть. И ссылку можно ставить слева от знака равенства. Значит, ссылка — это lvalue.
Окей, но ведь (почти любая) переменная тоже может быть слева от знака равенства. Значит, (такая) переменная — ссылка? Почти. Выражение, представляющее собой переменную — ссылка.
Этот принцип («выражение, являющееся переменной — ссылка») — моя выдумка. Т. е. ни в каком учебнике, стандарте и т. д. я этот принцип не видел. Тем не менее, он многое упрощает и его удобно считать верным. Если бы я реализовывал компилятор, я бы просто считал там переменные в выражениях ссылками, и, вполне возможно, именно так и предполагается в реальных компиляторах.
Более того, удобно считать, что особый тип данных для lvalue (т. е. ссылка) существует даже и в C. Именно так мы и будет дальше предполагать. Просто понятие ссылки нельзя выразить синтаксически в C, ссылку нельзя объявить.
Принцип «любое lvalue — ссылка» — тоже моя выдумка. А вот принцип «любая ссылка — lvalue» — вполне законный, общепризнанный принцип (разумеется, ссылка должна быть ссылкой на изменяемый объект, и этот объект должен допускать присваивание).
Операции * и &. Наши соглашения позволяют по-новому взглянуть на операции * и &. Теперь становится понятно следующее: операция * может применяться только к указателю (конкретно это было всегда известно) и она возвращает ссылку на тот же тип. & применяется всегда к ссылке и возвращает указатель того же типа. Таким образом, * и & превращают указатели и ссылки друг в друга. Т. е. по сути они вообще ничего не делают и лишь заменяют сущности одного синтаксиса на сущности другого! Таким образом, & вообще-то не совсем правильно называть операцией взятия адреса: она может быть применена лишь к уже существующему адресу, просто она меняет синтаксическое воплощение этого адреса.
Также замечу, что &*EXPR (здесь EXPR — это произвольное выражение, не обязательно один идентификатор) эквивалентно EXPR всегда, когда имеет смысл (т. е. всегда, когда EXPR — указатель), а *&EXPR тоже эквивалентно EXPR всегда, когда имеет смысл (т. е. когда EXPR — ссылка).
Массивы
Итак, есть такой тип данных — массив. Определяются массивы, например, так:
Выражение в квадратных скобках должно быть непременно константой времени компиляции в C89 и C++98. При этом в квадратных скобках должно стоять число, пустые квадратные скобки не допускаются.
то, опять-таки, место для массива будет целиком выделяться прямо внутри структуры, и sizeof от этой структуры будет это подтверждать.
Хорошо, будем считать, я вас убедил, что массив — это именно массив, а не что-нибудь ещё. Откуда тогда берётся вся эта путаница между указателями и массивами? Дело в том, что имя массива почти при любых операциях преобразуется в указатель на его нулевой элемент.
Конвертирование имени массива в void * или применение к нему == тоже приводит к предварительному преобразованию этого имени в указатель на первый элемент, поэтому:
Типы у участвовавших выражений следующие:
Массив нельзя передать как аргумент в функцию. Если вы напишите int x[2] или int x[] в заголовке функции, то это будет эквивалентно int *x и в функцию всегда будет передаваться указатель (sizeof от переданной переменной будет таким, как у указателя). При этом размер массива, указанный в заголовке будет игнорироваться. Вы запросто можете указать в заголовке int x[2] и передать туда массив длины 3.
Однако, в C++ существует способ передать в функцию ссылку на массив:
При такой передаче вы всё равно передаёте лишь ссылку, а не массив, т. е. массив не копируется. Но всё же вы получаете несколько отличий по сравнению с обычной передачей указателя. Передаётся ссылка на массив. Вместо неё нельзя передать указатель. Нужно передать именно массив указанного размера. Внутри функции ссылка на массив будет вести себя именно как ссылка на массив, например, у неё будет sizeof как у массива.
И что самое интересное, эту передачу можно использовать так:
Похожим образом реализована функция std::end в C++11 для массивов.
«Указатель на массив». Строго говоря, «указатель на массив» — это именно указатель на массив и ничто другое. Иными словами:
Однако, иногда под фразой «указатель на массив» неформально понимают указатель на область памяти, в которой размещён массив, даже если тип у этого указателя неподходящий. В соответствии с таким неформальным пониманием c и d (и b + 0 ) — это указатели на массивы.
А теперь посмотрим на такую ситуацию: