![]() |
Модераторы: bsa |
![]() ![]() ![]() |
|
bsa |
|
||||||||||||||||||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 9185 Регистрация: 6.4.2006 Где: Москва, Россия Репутация: 85 Всего: 196 |
Любой новичок, который решил изучить язык Си или С++, почти сразу же сталкивается с непониманием смысла "указателей" и "ссылок".
Указатель - это переменная или константа, содержащая адрес памяти, начиная с которого могут располагаться данные определенного типа (достаточно представить бумажку, на которой написан домашний адрес). Указатель не несет в себе информации о количестве данных (возьмите бумажку и попытайтесь по ней определить, сколько домов находится на той же улице). Можно получить адрес любой переменной (у всех домов есть адрес, не так ли?) и присвоить его подходящему указателю (номер телефона - на страницу телефонной книги, адрес - в адресной, email - в список контактов... - каждому свое место). Операция по получению доступа к данным, на которые указывает указатель, называется разыменованием. Пример:
Есть понятие дикий или подвисший указатель - это указатель непонятно куда. Он получается при создании переменной-указателя или после освобождения области памяти, в которую он указывал. Данными, на которые он указывает, пользоваться нельзя. В противном случае поведение программы непредсказуемо. Есть понятие нулевой указатель - это указатель в никуда. Обычно, он используется для информирования, что требуемая память не выделена, данные не найдены и пр. При попытке использовать данные, на которые он указывает, программа аварийно завершится (ошибка: "segmentation fault" или "access violation"). Пример:
Есть типизированные указатели (аналоги: адрес квартиры, кабинета, номер телефона) и нетипизированные (широта, долгота и высота над уровнем моря). Типизированные указатели используются в основном для работы с массивами однотипных данных (например, положить в почтовый ящик каждого жильца дома №10 листовку с рекламой). Поэтому для таких указателей определены операторы: сложения/вычитания целых чисел и вычитание указателей того же типа (квартира №10 находится через 6 квартир от квартиры №4: №10 - №4 = 6, №4 + 6 = №10...). Например, у нас есть массив вещественных чисел. А так же есть типизированный указатель, на первый элемент этого массива. Увеличение на 1 этого указателя приведет к тому, что он станет указывать на следующий элемент массива. Уменьшение - на предыдущий. А если взять два указателя, которые указывают на данные в одном массиве, то можно узнать, на какое количество элементов нужно переместить первый, чтобы получить второй - это делается вычитанием указателей (если взять указатели на разные массивы, то результатом будет какое-то относительно случайное число). Пример:
Нетипизированные указатели используются для работы с целыми областями памяти, когда тип лежащих там данных не имеет значения. Например, используется функцией копирования блока памяти (memcpy). Для подобных указателей не определены ни арифметические операции, ни операция разыменования (нельзя получить непосредственный доступ к данным). Пример:
Можно создать указатель на любой тип. Для этого необходимо при его объявлении поставить звездочку перед именем переменной:
Если нужно сделать typedef, то тут все очень просто - просто вместо имени переменной указываете название типа:
Стандартные библиотеки языков Си и С++ поддерживают перевод значений указателей в строковый вид, удобный для восприятия человеком. В принципе, это не особо нужно, разве что для отладки. Со времен языка Си указатели на char используются в качестве указателей на строки, именно поэтому стандартным поведением оператора вывода в поток (С++, std::ostream) на подобный указатель является отображение строки. Чтобы это избежать, указатель нужно привести к указателю на void: static_cast<const void*>(p) Преобразование указателей (и не только) в С и С++ немного отличается. В первом существует только один способ: Type *x = (Type*)y; Более того, преобразование любого указателя к указателю на void и обратно происходит молча - без лишних телодвижений. В С++ немного по другому - существует аж 4 вида преобразований (плюс, сохранен вариант из С): static_cast (преобразование совместимых типов), dynamic_cast (преобразование указателя на базовый класс к указателю на потомок), const_cast (снятие модификатора const с указателя) и reinterpret_cast (любое преобразование без проверки корректности). Эти преобразования расположены в порядке убывания предпочтительности использования. Последний из них аналогичен варианту из языка С. К тому же автоматическое преобразования указателя на void в указатель на другой тип отменено. Для этого необходимо использовать: Type *x = static_cast<Type*>(y); Ссылка была введена в С++ для упрощения передачи сложных структур в функции, чтобы избежать их копирования, которое сильно ухудшит скоростные показатели программы. Чтобы представить себе как она работает достаточно одного слова - псевдоним. Т.е. если у вас есть переменная x, то вы можете сделать ей псевдоним с именем y. Если вы измените y, то изменится и x, а если измените x, то аналогично изменится и y. Но нельзя сменить объект, с которым ассоциирована ссылка. Т.е. если вы сделали ссылку, как псевдоним для x, то вы не сможете уже сделать ее псевдонимом для z. Операция взятия адреса от ссылки приведет к тому, что будет возвращен адрес ассоциированного с ней объекта. Пример использования ссылок:
Назад к FAQ Это сообщение отредактировал(а) bsa - 26.7.2011, 11:01 |
||||||||||||||||||||
|
|||||||||||||||||||||
EgoBrain |
|
||||||||||||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 537 Регистрация: 23.3.2008 Где: Комната Репутация: нет Всего: 2 |
Можно продолжение по данной теме? Не затронуты такие аспекты как: указатель на указатель, передача в функцию указателя/указателя на указатель (пример был лишь с ссылкой), и чем отличается ссылка от указателя на уровне компилятора а не на логическом (если можно так выразиться).
Вот это, только Вашими словами:
И еще хотелось бы доп. объяснений по всяким синтаксическим хитростям типа (*z)++ и другое изащренное использование скобок и звездочек. |
||||||||||||
|
|||||||||||||
zim22 |
|
|||
![]() depict1 ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2682 Регистрация: 15.1.2009 Где: Украина Репутация: 29 Всего: 69 |
все подобные хитрости очень легко "парсятся" человеком, если знать(посмотреть) таблицу С++ операторов, а именно их приоритет и ассоциативность (лево/право) |
|||
|
||||
bsa |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 9185 Регистрация: 6.4.2006 Где: Москва, Россия Репутация: 85 Всего: 196 |
подумаю, скорее всего напишу кратенько про указатель на указатель. А вот на счет необходимости рассмотрения ссылки с точки зрения компилятора я не уверен - зачем новичку забивать голову лишним? Но если будет народ настаивать, то напишу. |
|||
|
||||
zim22 |
|
|||
![]() depict1 ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2682 Регистрация: 15.1.2009 Где: Украина Репутация: 29 Всего: 69 |
я против. новичку это ни к чему. Это сообщение отредактировал(а) zim22 - 22.9.2009, 14:08 |
|||
|
||||
ller |
|
|||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 325 Регистрация: 4.8.2008 Где: г. Таганрог Репутация: 2 Всего: 4 |
zim22, а не совсем новичкам? Тем кто уже общие аспекты знает, я думаю такая информация пригодится. Только указать
![]() |
|||
|
||||
EgoBrain |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 537 Регистрация: 23.3.2008 Где: Комната Репутация: нет Всего: 2 |
Если кто-то посчитает для себя эту информацию лишней, то не будет ее читать. Что касается глубины изучения на первых этапах, то я скажу, что на самом деле изучая такую точную математическую науку как программирования очень сложно балансировать между конкретикой и абстракционизмом, иной раз приходится сильно углублятся чтобы что-то понять, просто вот мне например зачастую очень сложно изучать на абстрактном уровне, так как на этом остаются вопросы.
|
|||
|
||||
wrathchildtoo |
|
|||
![]() Новичок Профиль Группа: Участник Сообщений: 17 Регистрация: 6.4.2009 Репутация: нет Всего: нет |
||||
|
||||
bsa |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 9185 Регистрация: 6.4.2006 Где: Москва, Россия Репутация: 85 Всего: 196 |
Почитать можно в книжках по С++ или в гугле. |
|||
|
||||
EgoBrain |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 537 Регистрация: 23.3.2008 Где: Комната Репутация: нет Всего: 2 |
Читайте закрепленную тему на этом же форуме! http://forum.vingrad.ru/articles/topic-60932.html Добавлено через 1 минуту и 15 секунд Просто я еще хотел услышать на этот счет мнение bsa |
|||
|
||||
bsa |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 9185 Регистрация: 6.4.2006 Где: Москва, Россия Репутация: 85 Всего: 196 |
EgoBrain, немного подправил про ссылки. Более глубоко рассказывать тут желания у меня нет.
|
|||
|
||||
EgoBrain |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 537 Регистрация: 23.3.2008 Где: Комната Репутация: нет Всего: 2 |
Очень интересно, дайте таблицу на русском. |
|||
|
||||
zim22 |
|
|||
![]() depict1 ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2682 Регистрация: 15.1.2009 Где: Украина Репутация: 29 Всего: 69 |
||||
|
||||
bsa |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 9185 Регистрация: 6.4.2006 Где: Москва, Россия Репутация: 85 Всего: 196 |
|
|||
|
||||
unicuum |
|
||||||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 830 Регистрация: 16.3.2005 Где: Рашка Репутация: нет Всего: 8 |
Вопрос в том, ставим ли мы звёздочку перед именем переменной или после указываемого типа. Я вот лично столкнулся с тем, что значки указателя (звёздочка) и ссылки (амперсанд) красивее выглядят присоединённых к типу, то есть не так:
Дело в ментальной модели мышления. Если я заранее знаю, что p - указатель на целочисленный тип, то и мысленно связываю его так же. Плюс есть ещё такая особенность, как пространства имён. Взять хотя бы класс, где объявление методов находится в его теле, которое помещено в заголовочный файл, а определение вложено в единицу компиляции. Или возвращение константной ссылки из метода класса. -------------------- ![]() обычный день на винграде |
||||||
|
|||||||
bsa |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 9185 Регистрация: 6.4.2006 Где: Москва, Россия Репутация: 85 Всего: 196 |
unicuum, не вижу смысла обсуждать подобные вещи. Это все из разряда, где ставить const - до названия типа или после, где ставить открывающую фигурную скобку, какой размер отступа нужно использовать... На вкус и цвет, как говорится...
|
|||
|
||||
baldina |
|
||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3433 Регистрация: 5.12.2007 Где: Москва Репутация: 15 Всего: 101 |
bsa,
Из примера не понятно, что там компилятор сможет "легко оптимизировать". и как это "легко" соотносится с
боюсь, для объяснения этого придется-таки поговорить о путях реализации |
||||
|
|||||
bsa |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 9185 Регистрация: 6.4.2006 Где: Москва, Россия Репутация: 85 Всего: 196 |
baldina, спасибо.
Подправил информацию про ссылки. |
|||
|
||||
Tobuk |
|
|||
Новичок Профиль Группа: Участник Сообщений: 29 Регистрация: 20.11.2008 Репутация: нет Всего: нет |
Так и не понял из темы зачем же нужны ссылки? Все же прекрасно получаеться с указателями.
Зачем использовать ссылки урезая тем самым себе возможности? Это сообщение отредактировал(а) Tobuk - 1.12.2009, 21:16 |
|||
|
||||
mes |
|
|||
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 79 Всего: 250 |
я бы перефразировал.. Ссылки ввели наряду с указателями, чтоб расширить возможности. ![]() |
|||
|
||||
unicuum |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 830 Регистрация: 16.3.2005 Где: Рашка Репутация: нет Всего: 8 |
Вот, имеем два противоположных мнения, пока что без намёка, что урезаем и что расширяем. -------------------- ![]() обычный день на винграде |
|||
|
||||
mes |
|
|||
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 79 Всего: 250 |
Почему без намека.. Tobuk, предположил что если ссылки нельзя "переставить", а также "хранить в них нуль", то они являются урезаными указателями. Однако тут забылось, что вышеуказанные два фактора нужны далеко не всегда, и во многих случаях будут заставлять программиста отвлекаться на лишние детали, чтоб гарантировать безопасность кода. |
|||
|
||||
unicuum |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 830 Регистрация: 16.3.2005 Где: Рашка Репутация: нет Всего: 8 |
Вот так сразу вспоминается только то, что ссылки в операторах используют, для возвращения *this, и потом на основе полученного строят выражения. А что ещё?
-------------------- ![]() обычный день на винграде |
|||
|
||||
mes |
|
|||
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 79 Всего: 250 |
||||
|
||||
Tobuk |
|
|||
Новичок Профиль Группа: Участник Сообщений: 29 Регистрация: 20.11.2008 Репутация: нет Всего: нет |
Вот пример:
Ссылки опасны, потому что нельзя понять как передаються аргументы в функцию(по значению или нет?). >Ссылки ввели наряду с указателями, чтоб расширить возможности. Что-что? Ссылки появились только в С++, а указатели были "открыты" еще задолго до C. Не вижу никакой выгоды от использования ссылок. Хотя я пишу на C и их не использую :-\ |
|||
|
||||
mes |
|
||||
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 79 Всего: 250 |
В других "безопасных" языках (тот же паскаль) тоже не заметно, но никого не смущает.. Кстати в них тоже "ссылочная" а не "указательная" передача параметров.
1. "наряду" это не "одновременно", а ближе к "в дополнение, на равных условиях" 2. ну и "ссылочность" как таковая изобретена задолго до C++ и даже до Си.. просто раньше называлось не передача по ссылке, а передача по имени. Ну а мне было бы мучительно без них .. Преимущества (основные в семантическом плане) 100 раз обсуждались - поиск поможет ![]() Это сообщение отредактировал(а) mes - 2.12.2009, 22:25 |
||||
|
|||||
bsa |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 9185 Регистрация: 6.4.2006 Где: Москва, Россия Репутация: 85 Всего: 196 |
Tobuk, ссылки нужны, чтобы гарантировать единообразие передачи параметров. Например, есть функция, которая принимает объекты типа std::string. Так как операция их копирования довольно длительной может быть, то было принято решение использовать ссылку. В результате, пользователь функции может вызвать ее с параметром типа std::string или типа const char *... Попробуй тоже самое сделать с указателями - ничего не получится. Более того, выглядеть будет как-то стремно, я уж не говорю о том, что код будет потенциально более опасен. Впрочем, Сишнику этого не понять.
|
|||
|
||||
baldina |
|
||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3433 Регистрация: 5.12.2007 Где: Москва Репутация: 15 Всего: 101 |
неправда
|
||||
|
|||||
djamshud |
|
|||
![]() Пердупержденный ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1655 Регистрация: 23.11.2009 Репутация: 4 Всего: 39 |
>void foo(/* by value */ int const& hello);
Ну щас.. Это тоже передача по ссылке. А чел кстати говорил про неясность в вызывающей функции: call(somevar); не ясно, изменит ли (гипотетически) call значение somevar или нет. Поэтому всегла, когда предполагается изменение передаваемых параметров, использую указатель. А ссылки рулят в случае ссылаемости на константу. Объекты передаются без копирования, а выглядит это, как обыный вызов. -------------------- 'Cuz I never walk away from what I know is right Alice Cooper - Freedom |
|||
|
||||
baldina |
|
||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3433 Регистрация: 5.12.2007 Где: Москва Репутация: 15 Всего: 101 |
технически - по ссылке, но семантически - по значению, т.к. значение аргумента изменить невозможно.
есть простой способ избежать неясностей - всегда использовать функциональный стиль, т.е. все результаты передаются через возвращаемое значение, аргументы не изменяются.
это могучий пример, но в реальном коде проблема носит скорее гипотетический характер: обычно тот, кто пишет/анализирует код, бывает в курсе, что и как делает call() ![]() Это сообщение отредактировал(а) baldina - 3.12.2009, 12:25 |
||||
|
|||||
mes |
|
|||
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 79 Всего: 250 |
вроде уже писал, но шас не нашел : 1. если человек знает сигнатуру функции то проблем нет, а если не знает, то что он вообще туда передает ?! 2. ну и названия функций следует подбирать так, чтоб было ясно, что может произойти внутри с аргументами. |
|||
|
||||
bsa |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 9185 Регистрация: 6.4.2006 Где: Москва, Россия Репутация: 85 Всего: 196 |
|
|||
|
||||
![]() ![]() ![]() |
Правила форума "C/C++: Для новичков" | |
|
Запрещается! 1. Публиковать ссылки на вскрытые компоненты 2. Обсуждать взлом компонентов и делиться вскрытыми компонентами
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, bsa. |
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | C/C++: Для новичков | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |