В ваших собственных исследованиях (самостоятельно или в классе) был ли у вас момент "ах-ха", когда вы, наконец, действительно поняли указатели? У вас есть объяснение, которое вы используете для начинающих программистов, которое кажется особенно эффективным?
Например, когда новички впервые сталкиваются с указателями в C, они могут просто добавлять &
s и *
s, пока он не скомпилируется (как я сам когда-то делал). Возможно, это была картинка или действительно хорошо мотивированный пример, который заставил указатели «щелкнуть» для вас или вашего ученика. Что это было, и что вы пробовали до того, как это не сработало? Были ли какие-то темы необходимыми условиями (например, структуры или массивы)?
Другими словами, что было необходимо для понимания значения &
s и *
когда вы могли бы использовать их с уверенностью? Изучение синтаксиса и терминологии или вариантов использования недостаточно, в какой-то момент идея должна быть усвоена.
Обновление: мне очень нравятся ответы до сих пор; пожалуйста, держите их в пути. Здесь много хороших перспектив, но я думаю, что многие из них являются хорошими объяснениями / лозунгами для нас после того, как мы усвоили эту концепцию. Я ищу подробные контексты и обстоятельства, когда вас осенило.
Например:
Я лишь немного понимал указатели синтаксически в C. Я слышал, как два моих друга объясняли указатели другому другу, который спросил, почему
struct
указатель был передан. Первый друг говорил о том, как на него нужно ссылаться и изменять, но это был просто короткий комментарий другого друга, где он меня ударил: «Это также более эффективно». Прохождение 4 байта вместо 16 байтов было последним концептуальным изменением, в котором я нуждался.
источник
Ответы:
Диаграмма памяти как сетки
Обычно я представляю память как «сетку», чтобы я мог составлять адреса, выделять различные области памяти и записывать в ячейки значения (или даже дальше, их двоичные представления) и связывать указатели в памяти со значениями, которые они указывать на. (А потом еще упомяните, что это упрощение).
Обычно это «оооо» момент для большинства моих учеников.
Символ жонглирования
Затем, когда дело доходит до того, что они перестают забывать, как использовать & и *, это очень просто: представьте это так же, как они выполняют математические или физические вычисления. Если вы разделите расстояние в км на время в часах, вы получите скорость в км / ч. Что должно быть вне. Просто.
printf на помощь
Выполнение всего лишь нескольких базовых примеров, которые наглядно представляют то, что вы объяснили, поможет им понять то, что, по их мнению, они поняли, или даст им возможность сказать «ах, я не понимаю этого».
Будьте обширны
Прикройте указатели для простых типов и убедитесь, что они понимают разницу между адресацией и размером типа данных, затем структуры, затем массивы и несколько уровней.
Затем начните указатель арифметики.
Приложение: рекурсия
Я обычно объясняю рекурсию аналогично, используя визуальное представление. Попросите их напечатать алфавит, используя готовую функцию, которая записывает один символ, а затем попросите их напечатать его в обратном порядке, просто изменив две строки.
Обычно есть "что за ...?" момент, и когда вы добавляете еще один параметр в ваш printf для печати числовых значений и отступа шагов, это становится вздохом облегчения.
Альтернативы: модель Play-Doh и чашки с водой
У меня на самом деле было несколько сотрудников в университете, которые показывали студентам видео с объяснениями указателей и обращений к памяти с использованием play-doh paste. Это было невероятно умно и хорошо сделано, хотя я никогда не использовал эту технику сам, за исключением очень молодых учеников, заинтересованных в понимании программирования (но обычно тех, кого я не привел бы к тому, чтобы язык использовал указатели слишком рано). В основном используются крошечные шарики play-doh, которые вы можете прикрепить к другим большим шарикам play-doh, представляющим пространства памяти, и которые вы можете объединить вместе, чтобы связать их (как в связанной структуре данных) или объединить вместе (как в смежных пространство памяти). Использование различных цветов для областей памяти, на которые указывают, и указатели также помогают. Но я все еще думаю, что «Память как сетка» работает лучше, как вы можете ясно показать, что указание действительно является вопросом «адресации», как на «карте / сетке». Принимая во внимание, что режим Play-doh все еще вводит их в заблуждение, будто они действительно «касаются» друг друга в памяти.
Коллега с Water Cup тоже использовалась коллегой, но я не знаю, придумала ли она ее. Это был интересный подход, но я заметил, что многие студенты были озадачены объяснением. Нечто подобное технике кофейной чашки DevSolo . Но я думаю, что это на самом деле вводит в заблуждение, поскольку вы заставляете студентов путать контейнеры, структуры данных, указатели и массивы. Я полагаю, это может быть интересным подходом для объяснения массивов в начале, но я бы не стал придерживаться этого очень долго.
источник
Кто-то намного мудрее, чем я когда-то сказал:
источник
Я обнаружил, что диаграммы были очень полезны. Пример:
Диаграмма такого типа помогла мне понять, что указатели были их собственной переменной, но содержали значение, которое было местоположением другого объекта, то есть массива или строки. Кроме того, когда это было сделано карандашом, я мог использовать его для отслеживания своей программы на бумаге или на доске / доске.
источник
Когда я впервые «узнал» об указателях, меня это как-то задело. Мой университет принял решение задолго до того, как я поступил, чтобы сосредоточить учебный план на Java, поэтому, когда мой профессор Data Structures прочитал одну лекцию по C и попросил нас создать XOR-List с указателями, я почувствовал, что что-то понимаю путь над моей головой.
Я понял определение:
Но я все еще не понял большую часть концепции. Оглядываясь назад, я думаю, что это сосредоточилось на трех вещах:
Что именно находится в памяти? (В то время я не посещал занятия по компьютерной организации)
Неловкий синтаксис (итак ... почему именно он определен как "int * ip", но затем впоследствии я называю переменную как "ip"?)
Как именно выгодно хранить адрес переменной, а не просто использовать переменную?
Только когда я купил книгу K & R и выполнил все задачи, я действительно получил представление об указателях. Помимо того факта, что я давно закончил класс Computer Organization (который, я думаю, должен быть необходим до изучения C), отчасти это связано с тем, что я понял, что указатели могут использоваться для функций, массивов, структур ... делать полезные вещи, а не просто как хранилище для адресов обычных переменных.
Но моим «ага» моментом было то, как K & R объяснил неловкий синтаксис определения простого указателя. Я делал заметки на протяжении всей книги (в которых я перефразирую высказанные в книге слова в свои слова, чтобы углубить мое понимание), и вот что относится к этому:
Я всегда чувствовал, что не могу полностью понять более продвинутые концепции указателей, пока в моей голове не появилось что-то настолько элементарное. После этого задания меня беспокоят бесконечно (кстати, я не очень хорошо справлялся;)), почему «* ip» не существовало сразу после того, как я (подумал, что я) определил «* ip». Освоение этого необходимо для более сложных концепций, включающих указатели, таких как указатели функций и более сложные определения, подобные этому:
В общем, я думаю, что концепция указателей требует:
Основное понимание того, как память размещена в компьютере (и что такое память).
Знание того, насколько мощными могут быть указатели (использование в реальном мире, а не просто еще одна абстрактная концепция, которую они изучают ради обучения).
Расшифровка иероглифов в разговорной речи известна как «определение указателя».
В общем, я думаю, что при изучении указателей должно быть не менее трех «ага» моментов. Я все еще студент, поэтому я подумал, что вы оцените точку зрения кого-то, кто еще (относительно) новичок в изучении этой концепции.
источник
PointerTo<int> a
]int* ip
не является более распространенным. Я наконец начал понимать указатели, как только увидел код, который был отформатирован следующим образом. Тогда я мог прочитать это как «ip имеет указатель типа int».Указатель немного похож на ярлыки приложений на рабочем столе. Удалите ярлык, и цель все еще существует. Запустите ярлык, и цель будет запущена.
Я всегда объясняю работу этого простым созданием txt-файла на моем рабочем столе и двумя ярлыками к файлу. После копирования и удаления ярлыков вы увидите, что люди понимают идею «ссылок».
Как только группа поймет, что стоит за ярлыками, вы можете начать объяснять указатели в любом случае. Они, вероятно, поймут это довольно легко.
источник
8-10 лет назад я преподавал вступительный курс "C" в общественном колледже. Это всегда была веселая тема для изучения. То, что, казалось, работало лучше всего, и это было после обсуждения с коллегой несколько раз, было использовать чашку кофе и вашу руку.
Я использовал аналогию кофейной чашки (или ряда из них для массивов) в качестве переменной (она может содержать что-то). Затем я использовал свою руку, которая также могла держать что-то или, вытянув указательный палец, чтобы «указывать на» кофейную чашку.
Близкая рука была нулевой, палец, указывающий на мою голову (как ложный пистолет), был висящим указателем.
Затем с несколькими демонстрациями и обходами отладчика он щелкнул большинством.
источник
Я действительно очень волнуюсь, когда слышу вопрос «как ты понял указатели». Я всегда думал, что концепция невероятно проста, и логическая эволюция языков обеспечивает большую мощь для программистов.
Меня беспокоит то, что мне никогда не было трудно понять концепцию указателей. Поэтому, когда вы здесь «когда вы, наконец, получили это» снова и снова, вы начинаете думать:
Может быть, причина, по которой эта концепция кажется хитрой, заключается в том, что мы постоянно говорим всем, кто еще не сталкивался с ними, что указатели настолько сложны, и вот вам сто способов, которыми вы можете научиться?
Просто добавив эту идею, конечно, лично я люблю хорошую диаграмму, и Стив Гибсон всегда делает фантастическую работу, объясняя что-нибудь !
источник
У меня никогда не было большой проблемы с указателями в C, но это может быть потому, что мне сначала пришлось выучить ассемблер. На самом деле это было облегчением - мне больше не нужно было управлять адресами. Поэтому, возможно, ответ (при условии, что вы этому учите) состоит в том, чтобы дать студентам эмулированный язык ассемблера для работы. Они будут выяснить это в процессе написания ничего более сложного , чем «Привет, мир.»
источник
Указатель - это переменная, значением которой является адрес памяти другой переменной.
источник
Как я действительно узнал об указателях? Написав простой компилятор первокурсников год колледжа.
Как объяснить указатели с точки зрения непрофессионала? Мне нравится (датированная?) Аналогия библиотечного каталога, хранящегося на карточках. Каждая карточка («указатель») содержит информацию о том, где находится какая-то книга («данные»), но на самом деле сама книга не содержит. Если вы изменяете карту («арифметика указателей»), все, что она делает, это изменяет книгу, на которую она указывает, и не влияет на саму книгу - просто будьте осторожны, чтобы не испортить адрес, иначе вы можете указать на несуществующую книгу или даже не та библиотека. Однако, если вы будете следовать «адресу» на карточке и перейдете к нужной части библиотеки («разыменовать указатель»), вы сможете просмотреть / изменить саму книгу.
источник
Я предполагаю, что кто-то, изучающий указатели, знает, что такое обычные переменные и как они работают в C. Теперь давайте попробуем определить указатели с некоторыми из его атрибутов.
Они тоже переменные, но разной природы. Предположим, что в пространстве переменных есть два слоя. Нормальные переменные разных типов находятся в верхнем слое и указатели в нижнем слое. Как эта фигура
Как следует из названия «Указатель», указатели могут указывать на что-то. Как наш палец может указывать на какой-то объект. На что они указывают? Это нормальные переменные. Короче говоря, «Указатели указывают на нормальные переменные».
Итак, как указатель объявлен? Почти как обычные переменные. Перед именем нужно поставить звездочку (
*
). Подобно-Тогда, как указатель связан с переменной? Использование
&
оператора перед переменной, как это утверждениеКак указатель используется, указывая на переменную? Это также можно сделать, поставив перед именем звездочку (
*
). Затем его можно использовать вместо переменной, на которую он указываетвместо
Теперь поиграйте с указателями с некоторым кодом. Просто привыкните к этой характеристике указателей сейчас. До этого момента мы говорим о том, что делают указатели. Как только вы освоитесь, начните изучать, как указатели указывают на некоторую переменную и как они реагируют, если к ним применяются обычные арифметические операции. Затем перейдите к связи между указателями и массивами и указателями на указатели.
Это все, что я предлагаю по поводу изучения указателей.
источник
Отредактировано в поддержку пересмотренного требования вопроса
Мой путь к пониманию «пост-указатель» (если я правильно помню) пошел следующим образом. У меня был некоторый простой опыт программирования на ассемблере, когда я еще играл с BBC Micro, поэтому у меня была концепция памяти в виде набора блоков (см. Ниже). Это было подкреплено использованием массивов. Тем не менее, я собирался в мир C и должен был иметь дело со строками, а это означало указатели. В BASIC это было тривиально, в ассемблере мне никогда не приходилось с ними работать, а теперь в классическом C это все указатели и прочее. Ах, но я могу вернуться к массивам с (завершенными нулем) строками так:
Все хорошо, это просто массив символов (8 бит на символ в моем маленьком мире) с нулевым символом в конце, чтобы показать, где он заканчивается. Printf просто берет этот массив и запускает его, печатая. Но что, если я хочу передать эту строку в функцию?
О чем говорится в руководстве, но о чем это все? Хм, char * означает «указатель на символ». ОК ... потерял меня. Затем до меня дошло, что char * делает p эквивалентным s [0]. Хорошо, я могу использовать это, но я все еще не понял, что это за указатели. Я имею в виду, как я могу установить некоторые данные с одной из этих вещей? Снова к руководству ...
Когда я пишу выше, я говорю себе: «объявите указатель на символ и установите его равным этому массиву символов». Каким-то образом этот указатель устраняет необходимость в массиве. Думаю, это компилятор, делающий что-то для меня. Так как я могу изменить массив с этим указателем? Я знаю, что я мог бы использовать версию массива
но что эквивалентно в «указатель говорят»? Снова к этому руководству ...
Я предполагаю, что * просто означает «содержимое адреса памяти» и
(p+2)
естьs[2]
. Что означало, что указатель p был ... просто ... адресом ... бонгом!Что есть звук просветления. Я внезапно щелкнул указателями (это было очень давно, мы, старожилы, не «ухмылялись» до позднего времени). Это было просто косвенное.
Оригинал:
ОК, мой 2с стоит:
Представьте, что память - это куча коробок. Каждое поле имеет номер на стороне (адрес). Каждая коробка содержит номер (содержимое). Вы можете работать с этими блоками двумя способами: переменные (мне нужно содержимое блока N), указатели (мне нужно содержимое блока, которое находится в блоке N ). Указатели просто косвенные.
И для большого ответа, который охватывает все, что вам когда-либо нужно будет знать - прочитайте это .
источник
Возьми несколько маленьких кусочков дерева.
добавьте металлические крючки к одному концу и металлические глазки к другому.
Теперь вы можете сделать связанный список в материале, с которым вы можете играть.
Попробуйте объяснить с помощью этой физической опоры. Мне часто хотелось, чтобы у меня было это, когда я учил студентов-первокурсников.
Маленький металлический крючок - это указатель, а деревянная глыба - на что указывает вещь.
Я защищаю любого, чтобы не получить его после игры с блоками.
источник
Я сделал мою жизнь проще, когда я просто удалил весь пух и начал рассматривать указатель как любую другую переменную, а не какую-то магическую сущность (давным-давно в 11 классе) ... просто знаю 3 вещи:
Все остальное - синтаксический сахар и здравый смысл. Просто напишите несколько простых программ на C (например, реализацию библиотеки связанных списков), используя указатели, чтобы освоить их.
источник
источник
Я не могу вспомнить обстоятельства, связанные с моими указателями, ага, но я задним числом восстановил воспоминания о моем понимании массива в стиле c. (т.е.
arr[3]
такой же как*(arr+3)
)По некоторым причинам я нахожу чрезвычайно полезным просматривать указатели как массивы всякий раз, когда я сталкиваюсь с ситуацией указателя.
источник
В основном @Gary Rowe представил правильную модель. Память как набор ящиков с адресами (номерами) на них. В каждом поле хранится значение (число).
Идея указателя состоит в том, чтобы интерпретировать значение в одном блоке как адрес другого блока. Это значение используется для ссылки на конкретное поле, поэтому оно называется ссылкой . Таким образом, разыменование - это процесс открытия окна, на которое ссылаются.
если
v
это переменная (блок), то операторv
означает ценностьv
, т.е. дай мне то, что находится в коробке*v
означает разыменование значенияv
, т. е. дать мне то, что находится в поле, на которое ссылается значениеv
&v
значит ссылкаv
, т.е. дай мне адрес на коробкеЯ думаю, что это не соответствует цели введения указателей как чего-то совершенно другого. Это была концепция, которую трудно понять, когда я был ребенком. Это всегда казалось какой-то темной магией, которую я никогда не понимал по-настоящему, для которой требовалось много специальных персонажей. В первый раз я понял, когда написал маленькую игру, использующую двойное косвенное обращение в языке, в котором нет арифметики указателей. Это просветило меня.
Указатели - это вопрос интерпретации. Я думаю, что объяснение делает вещи намного проще. Арифметика указателей - чрезвычайно простые и интуитивно понятные операции, если показать простой пример с памятью из 10 переменных.
источник
Объяснение, которое я действительно взломал, было:
источник
Если вы хотите объяснить указатели, вы должны сначала объяснить память. Я обычно делаю это, используя миллиметровку / прямоугольную бумагу со строками и столбцами. Если «ученик» понимает память, он может понять, что такое адрес. Если у вас есть адрес, у вас есть указатели.
Вы можете играть с этой абстракцией. Например, напишите адрес (номер) одного квадрата в другой квадрат. Теперь нарисуйте стрелку от квадрата указателя до квадрата назначения. Теперь перезапишите указатель (например, увеличьте его) и отрегулируйте стрелку. Запишите адрес в другой квадрат и позвольте ученику нарисовать стрелку ...
Следующий шаг: присвойте определенным квадратам (например, указателю) имя. Теперь вы можете объяснить разыменование. Вот и все.
источник
Возможно, это только я, но я хорошо работаю с аналогиями. Допустим, у вас есть друг (функция / класс) "Foo", который хочет, чтобы кто-то другой (другая функция / класс), "Бар", связался с вами по какой-то причине. «Foo» может заставить вас пойти посмотреть «Бар», но это не удобно, перемещая все эти существа (экземпляры) вокруг. Однако «Foo» может отправить «Бар» ваш номер телефона (указатель). Таким образом, независимо от того, где вы находитесь, «Foo» знает, как связаться с вами, не находя вас.
И, скажем, у «Бар» есть знакомый «Баз», который тоже хочет с вами связаться. Но вы защищаете свой номер телефона и не хотите, чтобы все имели, «Баз» может позвонить «Бар» (телефон в качестве указателя), который затем может переадресовать вам (другой указатель). И так далее, и далее по цепочке друзей «Баз» и друзей друзей.
источник
Указатели сделать путем больше смысла , если вы изучали язык ассемблера и / или компьютерную архитектуру. Я думаю, что если бы я преподавал класс C, я бы начал с пары недель архитектуры, чтобы объяснить модель памяти и виды инструкций, которые фактически выполняет процессор.
источник
Мое "ага!" Настал момент в этом уроке:
Учебник по указателям и массивам в C
Чтобы быть точным, это пришло в этой главе: Глава 3: Указатели и строки
Чтобы быть еще более точным, это пришло с этим предложением:
Когда я прочитал это, облака разошлись, и ангелы взорвали трубные фанфары.
Ведь каждый учебник или книга по Си, которые я читал до этого, утверждали, что Си может передать по значению или по ссылке гнусную ложь. Правда в том, что C всегда передается по значению, но иногда передаваемое значение бывает адресом. Внутри метода создается копия этого адреса, точно так же, как создается копия переданного типа int. Копия не создается из значения, на которое указывает указатель. Таким образом, используя указатель внутри метода, вы можете получить доступ к исходному значению и изменить его.
Я никогда не становился программистом C, но я стал программистом .NET, и объекты и ссылки на объекты работают одинаково; ссылка на объект передается по значению (и, следовательно, копируется), но сам объект не копируется. Я работал со многими программистами, которые не понимают этого, потому что они никогда не изучали указатели.
источник
Хитрость заключается в том, чтобы объяснить, что местоположение вещи и сама вещь не одно и то же, точно так же, как изображение трубы - это не труба . Когда вы перемещаете вещь, ее местоположение меняется. Место остается, и кое-что еще можно положить туда.
источник
Указатель - это заметка, которая говорит вам, где что-то полезное. Он содержит местоположение вещи и говорит вам, насколько она велика (во всяком случае, в C). Таким образом, двойной указатель похож на заметку с надписью «В холодильнике шесть упаковок». Вы должны пойти за шестью пачками, чтобы выяснить, кола это или Budweiser.
источник
Учитывая код:
int v=42;
// объявляем и инициализируем простую переменнуюint *p = &v;
// создаем точку p для переменной vО вышеприведенном коде можно сказать следующее:
int * p
// "указатель int p" ... так вы объявляете указатель на переменную типа int*p
// "указывает на p" ... это данные, на которые указывает p, то же самое, что и v.&v
// "адрес переменной v" ... это представляет буквальное значение для pисточник
http://cslibrary.stanford.edu/
На этом сайте есть отличные учебники для изучения указателей и управления памятью.
Я бы посоветовал вам пройтись по основам указателей, указателям и памяти, приведенным на сайте. Вы также можете посмотреть на проблемы со связанными списками, приведенными по ссылке, чтобы еще больше усилить концепцию указателей.
источник
Ключ к объяснению указателей - убедиться, что люди, которым вы объясняете, уже понимают концепцию памяти. Хотя было бы неплохо, если бы они действительно поняли его на низком уровне, полагая, что память существует как массивный массив, и понимания того, что вы можете получить доступ к любой позиции в массиве по ее местоположению индекса, достаточно.
Следующий шаг, имеющий концепцию передачи местоположения индекса, а не копирования всей памяти, имеет смысл для большинства людей. И этого достаточно, чтобы позволить большинству людей понять, почему указатели полезны.
последний шаг к пониманию указателей - объяснить, как можно передать в качестве параметра местоположение индекса памяти для метода хранения местоположения индекса, где хранятся все данные. Я обнаружил, что это может быть слишком далеко для некоторых людей.
После того, как кто-то освоил эти основные шаги, им сразу становится понятно, что вы можете бесконечно связывать указатели, пока вы отслеживаете, сколько раз вам нужно просматривать адреса, чтобы найти фактический объект данных.
После того, как кто-то понял указатели, следующая вещь, которую он должен понять, это разница между кучей памяти и памятью стека, и почему указатели на память стека опасны, когда передаются вне метода.
источник
Я помню книгу «С загадки» или похожую, которую я прочитал просто потому, что это была одна из немногих книг по программированию / компьютерам, доступных в библиотеке, мое понимание С было зачаточным. Он бросил в вас C-выражение и попросил объяснить это, становясь все более и более сложным.
источник
Когда я учился в университете, у моего профессора были действительно аккуратные слайды PowerPoint, изображающие точку как отдельную переменную со стрелкой в ячейке памяти (представленной в виде массива), и когда мы делали связанные списки, он делал это шаг шаг за шагом, показывающий, когда стрелка меняется, когда указатель разыменовывается и т. д., никто не мог этого понять в течение пары минут. Сама концепция действительно проста, но правильное выполнение или применение в практических программах требует больше практики.
источник
Прежде чем я это сделаю, я объясню, что в программировании «все использует память» и (статическое) распределение переменных в памяти. Я также объясню, что такое адрес памяти и связь между пространством памяти, адресом памяти и переменными.
Наконец, я объясняю, что существуют целочисленный тип данных и переменные, строковый тип данных и переменные ... и так далее, пока не объясним, что существует специальный тип данных, который хранит адреса памяти, который имеет пустое значение, например 0 o "", называется ноль .
И, наконец, динамически распределяемые переменные посредством использования указателей.
источник