![]() |
Модераторы: 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 - указатель на целочисленный тип, то и мысленно связываю его так же. Плюс есть ещё такая особенность, как пространства имён. Взять хотя бы класс, где объявление методов находится в его теле, которое помещено в заголовочный файл, а определение вложено в единицу компиляции. Или возвращение константной ссылки из метода класса. -------------------- ![]() обычный день на винграде |
||||||
|
|||||||
![]() ![]() ![]() |
Правила форума "C/C++: Для новичков" | |
|
Запрещается! 1. Публиковать ссылки на вскрытые компоненты 2. Обсуждать взлом компонентов и делиться вскрытыми компонентами
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, bsa. |
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | C/C++: Для новичков | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |