Какое хорошее объяснение для указателей? [закрыто]


72

В ваших собственных исследованиях (самостоятельно или в классе) был ли у вас момент "ах-ха", когда вы, наконец, действительно поняли указатели? У вас есть объяснение, которое вы используете для начинающих программистов, которое кажется особенно эффективным?

Например, когда новички впервые сталкиваются с указателями в C, они могут просто добавлять &s и *s, пока он не скомпилируется (как я сам когда-то делал). Возможно, это была картинка или действительно хорошо мотивированный пример, который заставил указатели «щелкнуть» для вас или вашего ученика. Что это было, и что вы пробовали до того, как это не сработало? Были ли какие-то темы необходимыми условиями (например, структуры или массивы)?

Другими словами, что было необходимо для понимания значения &s и *когда вы могли бы использовать их с уверенностью? Изучение синтаксиса и терминологии или вариантов использования недостаточно, в какой-то момент идея должна быть усвоена.


Обновление: мне очень нравятся ответы до сих пор; пожалуйста, держите их в пути. Здесь много хороших перспектив, но я думаю, что многие из них являются хорошими объяснениями / лозунгами для нас после того, как мы усвоили эту концепцию. Я ищу подробные контексты и обстоятельства, когда вас осенило.

Например:

Я лишь немного понимал указатели синтаксически в C. Я слышал, как два моих друга объясняли указатели другому другу, который спросил, почему structуказатель был передан. Первый друг говорил о том, как на него нужно ссылаться и изменять, но это был просто короткий комментарий другого друга, где он меня ударил: «Это также более эффективно». Прохождение 4 байта вместо 16 байтов было последним концептуальным изменением, в котором я нуждался.


16
Метод дробовика: бросайте * s везде, пока это не работает.
Майкл К

15
@Michael: Да, удачи тебе в этом.
Роберт Харви

8
Этот вопрос возникает вскоре после начала каждого семестра в SO. Последнее воплощение здесь: stackoverflow.com/questions/4118647/…
Тим Пост

10
Какое хорошее объяснение для указателей? Брайан Керниган и Деннис Ритчи ненавидят разработчиков программного обеспечения.
Адам Кроссленд

3
Он «щелкнул» для меня, потратив некоторое время на пошаговый машинный код в отладчике. Да, я был знаком с основами компьютерной архитектуры - я изучал ассемблер на Commodore 64, и x86 ASM был довольно простым после этого. Таким образом, я уже знал понятие «адрес», я просто не понимал, как оно сопоставляется с синтаксическими конструкциями Си.
zvrba

Ответы:


25

Диаграмма памяти как сетки

Обычно я представляю память как «сетку», чтобы я мог составлять адреса, выделять различные области памяти и записывать в ячейки значения (или даже дальше, их двоичные представления) и связывать указатели в памяти со значениями, которые они указывать на. (А потом еще упомяните, что это упрощение).

Обычно это «оооо» момент для большинства моих учеников.

Символ жонглирования

Затем, когда дело доходит до того, что они перестают забывать, как использовать & и *, это очень просто: представьте это так же, как они выполняют математические или физические вычисления. Если вы разделите расстояние в км на время в часах, вы получите скорость в км / ч. Что должно быть вне. Просто.

printf на помощь

Выполнение всего лишь нескольких базовых примеров, которые наглядно представляют то, что вы объяснили, поможет им понять то, что, по их мнению, они поняли, или даст им возможность сказать «ах, я не понимаю этого».

Будьте обширны

Прикройте указатели для простых типов и убедитесь, что они понимают разницу между адресацией и размером типа данных, затем структуры, затем массивы и несколько уровней.

Затем начните указатель арифметики.


Приложение: рекурсия

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

Обычно есть "что за ...?" момент, и когда вы добавляете еще один параметр в ваш printf для печати числовых значений и отступа шагов, это становится вздохом облегчения.


Альтернативы: модель Play-Doh и чашки с водой

У меня на самом деле было несколько сотрудников в университете, которые показывали студентам видео с объяснениями указателей и обращений к памяти с использованием play-doh paste. Это было невероятно умно и хорошо сделано, хотя я никогда не использовал эту технику сам, за исключением очень молодых учеников, заинтересованных в понимании программирования (но обычно тех, кого я не привел бы к тому, чтобы язык использовал указатели слишком рано). В основном используются крошечные шарики play-doh, которые вы можете прикрепить к другим большим шарикам play-doh, представляющим пространства памяти, и которые вы можете объединить вместе, чтобы связать их (как в связанной структуре данных) или объединить вместе (как в смежных пространство памяти). Использование различных цветов для областей памяти, на которые указывают, и указатели также помогают. Но я все еще думаю, что «Память как сетка» работает лучше, как вы можете ясно показать, что указание действительно является вопросом «адресации», как на «карте / сетке». Принимая во внимание, что режим Play-doh все еще вводит их в заблуждение, будто они действительно «касаются» друг друга в памяти.

Коллега с Water Cup тоже использовалась коллегой, но я не знаю, придумала ли она ее. Это был интересный подход, но я заметил, что многие студенты были озадачены объяснением. Нечто подобное технике кофейной чашки DevSolo . Но я думаю, что это на самом деле вводит в заблуждение, поскольку вы заставляете студентов путать контейнеры, структуры данных, указатели и массивы. Я полагаю, это может быть интересным подходом для объяснения массивов в начале, но я бы не стал придерживаться этого очень долго.


Вау, спасибо за награду. Рад, что ответ был оценен.
Хайлем

Нарисуй это: | это звучит как хорошее учение!
Spooks

80

Кто-то намного мудрее, чем я когда-то сказал:

Монахиня Ву Джинканг спросила Шестого Патриаха Хуиненга: «Я изучала сутру Махапаринирваны в течение многих лет, но есть много областей, которые я не совсем понимаю. Пожалуйста, просветите меня».

Патриарх ответил: «Я неграмотен. Пожалуйста, зачитайте мне символы, и, возможно, я смогу объяснить смысл».

Сказала монахиня: «Ты даже не узнаешь персонажей. Как ты тогда можешь понять смысл?»

«Истина не имеет ничего общего со словами. Истину можно сравнить с яркой луной в небе. Слова в этом случае можно сравнить с пальцем. Палец может указывать на местоположение луны. Однако палец не является луна. Чтобы смотреть на луну, нужно смотреть за палец, верно?


13
+1 за разыменование луны. +1 за коан, если бы мог.
Тим Пост

14
Что за звук одного пальца?
Адам Кроссленд

3
@ Adam, это зависит от того, используете ли вы мышь или трекпад.
Даниэль Джозеф

7
@Frank Это была БОЛЬШАЯ цитата. Тем не менее, я думаю, что это не поможет понять идею. Специально для кого-то нового для указателей.
Гульшан

11
Это красивая история ... но я подозреваю, что люди голосуют за это, а не потому, что это хорошо объясняет указатели.
Kyralessa

46

Я обнаружил, что диаграммы были очень полезны. Пример:

диаграмма указателя


Диаграмма такого типа помогла мне понять, что указатели были их собственной переменной, но содержали значение, которое было местоположением другого объекта, то есть массива или строки. Кроме того, когда это было сделано карандашом, я мог использовать его для отслеживания своей программы на бумаге или на доске / доске.


4
Либо значение в «указателе» должно быть 4, либо индексы массива (или адреса памяти) должны начинаться с 0. В противном случае, как указатель, содержащий значение 3, может указывать на расположение 4?
МАК

++ Это именно то, как я собирался объяснить это. Я начал в Фортране (лучше или хуже!). В Фортране, в то время, мы использовали параллельные массивы вместо массивов структур (такого понятия, как new ). Если один массив содержал индекс «другой строки» в массивах, мы называли его «указателем», и это было захватывающе. Мы создали связанные списки, деревья, вы называете это.
Майк Данлавей

2
Я считаю, что указатели лучше всего объясняются с помощью картинок, указывающих, где хранится, и стрелками, указывающими, куда указывают указатели.
Габлин

32

Когда я впервые «узнал» об указателях, меня это как-то задело. Мой университет принял решение задолго до того, как я поступил, чтобы сосредоточить учебный план на Java, поэтому, когда мой профессор Data Structures прочитал одну лекцию по C и попросил нас создать XOR-List с указателями, я почувствовал, что что-то понимаю путь над моей головой.

Я понял определение:

Указатель - это переменная, которая содержит адрес переменной

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

  1. Что именно находится в памяти? (В то время я не посещал занятия по компьютерной организации)

  2. Неловкий синтаксис (итак ... почему именно он определен как "int * ip", но затем впоследствии я называю переменную как "ip"?)

  3. Как именно выгодно хранить адрес переменной, а не просто использовать переменную?

Только когда я купил книгу K & R и выполнил все задачи, я действительно получил представление об указателях. Помимо того факта, что я давно закончил класс Computer Organization (который, я думаю, должен быть необходим до изучения C), отчасти это связано с тем, что я понял, что указатели могут использоваться для функций, массивов, структур ... делать полезные вещи, а не просто как хранилище для адресов обычных переменных.

Но моим «ага» моментом было то, как K & R объяснил неловкий синтаксис определения простого указателя. Я делал заметки на протяжении всей книги (в которых я перефразирую высказанные в книге слова в свои слова, чтобы углубить мое понимание), и вот что относится к этому:

Указатель - это переменная, которая содержит адрес переменной. Указатель определяется и разыменовывается (получая значение, хранящееся в той области памяти, на которую он указывает) с помощью оператора '*'; выражение мнемоническое.

Ex.: 
   int a;      /* Variable 'a' is an integer */

   int *ip;   /* Variable ip is a pointer and dereferencing it gives an integer.
                 In other words, the expression *ip is an int, so ip is a pointer
                 to an int */

Я всегда чувствовал, что не могу полностью понять более продвинутые концепции указателей, пока в моей голове не появилось что-то настолько элементарное. После этого задания меня беспокоят бесконечно (кстати, я не очень хорошо справлялся;)), почему «* ip» не существовало сразу после того, как я (подумал, что я) определил «* ip». Освоение этого необходимо для более сложных концепций, включающих указатели, таких как указатели функций и более сложные определения, подобные этому:

char (*(x())[])()

В общем, я думаю, что концепция указателей требует:

  1. Основное понимание того, как память размещена в компьютере (и что такое память).

  2. Знание того, насколько мощными могут быть указатели (использование в реальном мире, а не просто еще одна абстрактная концепция, которую они изучают ради обучения).

  3. Расшифровка иероглифов в разговорной речи известна как «определение указателя».

В общем, я думаю, что при изучении указателей должно быть не менее трех «ага» моментов. Я все еще студент, поэтому я подумал, что вы оцените точку зрения кого-то, кто еще (относительно) новичок в изучении этой концепции.


+1 за 3 "Ах, ха!" monents. Указатели Groking приходят в слоях. Я «понимал» моменты в течение долгого времени, прежде чем понял, что только наполовину понял указатели на указатели :)
Binary Worrier

Я думаю, что вы абсолютно правы в том, что очень большая часть «непонимающих указателей» фактически использует странный синтаксис Си. [Думает: мне интересно, как трудно было бы впихнуть такой синтаксис: PointerTo<int> a]
Бенджол

Согласен, @Benjol. Я удивлен, что синтаксис int* ipне является более распространенным. Я наконец начал понимать указатели, как только увидел код, который был отформатирован следующим образом. Тогда я мог прочитать это как «ip имеет указатель типа int».
Джейкоб

19

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

Я всегда объясняю работу этого простым созданием txt-файла на моем рабочем столе и двумя ярлыками к файлу. После копирования и удаления ярлыков вы увидите, что люди понимают идею «ссылок».

Как только группа поймет, что стоит за ярлыками, вы можете начать объяснять указатели в любом случае. Они, вероятно, поймут это довольно легко.


Это не плохая аналогия. Всего несколько пунктов, которые можно добавить для любого, кто воспринимает это буквально как «жесткую ссылку», всегда будет указывать на его цель, даже если он меняет каталоги, указатель будет указывать на исходную память, даже если объект был перемещен. «Жесткая ссылка» скажет вам, когда цель больше не существует, указатель повисшего указателя должен быть установлен в NULL.
snmcdonald

Жесткая ссылка похожа на умный указатель с подсчетом ссылок
jk.

1
+1. Одна из лучших практических аналогий для объяснения указателей. Я уверен, что студенты поняли бы идею немедленно, поскольку эта функциональность является наиболее часто используемой всеми.
Картик Сринивасан

13

8-10 лет назад я преподавал вступительный курс "C" в общественном колледже. Это всегда была веселая тема для изучения. То, что, казалось, работало лучше всего, и это было после обсуждения с коллегой несколько раз, было использовать чашку кофе и вашу руку.

Я использовал аналогию кофейной чашки (или ряда из них для массивов) в качестве переменной (она может содержать что-то). Затем я использовал свою руку, которая также могла держать что-то или, вытянув указательный палец, чтобы «указывать на» кофейную чашку.

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

Затем с несколькими демонстрациями и обходами отладчика он щелкнул большинством.


3
Вы уже запутали меня.
kirk.burleson

1
@ Кирк, как так? дай мне посмотреть, смогу ли я это прояснить.
DevSolo

4
++ Нет ничего лучше, чем учить вас думать об этих вещах.
Майк Данлавей

Один из моих преподавателей в университете сделал то же самое, используя студентов (одним из которых был «Ниль», для дополнительного смеха) вместо кофейной чашки. Указывая рукой на зрителей, это был висящий указатель, потому что он мог указывать на что угодно.
Каз Драгон

2
Свисающий указатель больше похож на указание на Нейла, затем заставляет его покинуть кресло, не меняя места, куда вы указываете ... затем пытаясь следовать этому указателю и интерпретировать то, что вы найдете там, как Нила, независимо от того, кто там оказался.
Джон Пурди,

10

Я действительно очень волнуюсь, когда слышу вопрос «как ты понял указатели». Я всегда думал, что концепция невероятно проста, и логическая эволюция языков обеспечивает большую мощь для программистов.

Меня беспокоит то, что мне никогда не было трудно понять концепцию указателей. Поэтому, когда вы здесь «когда вы, наконец, получили это» снова и снова, вы начинаете думать:

Я действительно понимаю? Может я никогда не делал?

Может быть, причина, по которой эта концепция кажется хитрой, заключается в том, что мы постоянно говорим всем, кто еще не сталкивался с ними, что указатели настолько сложны, и вот вам сто способов, которыми вы можете научиться?

Просто добавив эту идею, конечно, лично я люблю хорошую диаграмму, и Стив Гибсон всегда делает фантастическую работу, объясняя что-нибудь !


Интересно ... какой язык вы использовали в то время? Я думаю, что синтаксис Си сбивает с толку многих людей. Если бы вы знали сборку в первую очередь, я бы понял, что это одна из причин. [Кстати, я хочу проголосовать за это, но сегодня я достиг предела.]
Макнейл

Интересно, что я давно не знал «опасных» указателей, работая на Python (и Java в университете). Затем я взял модуль «объектно-ориентированные методы», который использовал C ++ в качестве языка выбора, и сразу же углубился в него.
Маркус Уайброу

Также я думаю, что понимание того, как программа представлена ​​в памяти, безусловно, может помочь, но я бы предпочел сказать, что понимание того, почему указатели были полезным дополнением к языку, является наиболее эффективным углом зрения, поскольку вы проходите то же самое, хотя процесс как оригинальные дизайнеры.
Маркус Уайброу

+1 Я понятия не имею, почему люди думают, что указатели сложны или загадочны.
ggambett

Да, указатели всегда были настолько просты и полезны, что я не могу представить, что в них есть что-то «сложное». Я ненавижу, когда учитель любого курса говорит: «Теперь это немного сложно», потому что это так подрывно. Просто научите этому чертову штуку, и пусть ученики сами решат, считают ли они, что это сложно.
Джон Пурди,

7

У меня никогда не было большой проблемы с указателями в C, но это может быть потому, что мне сначала пришлось выучить ассемблер. На самом деле это было облегчением - мне больше не нужно было управлять адресами. Поэтому, возможно, ответ (при условии, что вы этому учите) состоит в том, чтобы дать студентам эмулированный язык ассемблера для работы. Они будут выяснить это в процессе написания ничего более сложного , чем «Привет, мир.»


+1 за адаптацию более примитивной абстракции, вместо того, чтобы пытаться использовать аналогию.
анонимный тип

В моей средней школе одно подразделение компьютерных исследований было посвящено изучению спичечного компьютера , которому можно учить с доски, даже не касаясь реального компьютера.
Руон

@ Ларри Коулман, Ассамблея !!!!!!!!!!! Я хочу попробовать это до C. Пожалуйста, скажите мне, где начать учиться. Бесплатные электронные книги, бесплатные PDF? IDE? Пожалуйста!!!!!!!!!!!!!!!!!!!
Spacez Ly Wang

7

Указатель - это переменная, значением которой является адрес памяти другой переменной.


Элегантно, зачем усложнять.
Бьярке Фрейнд-Хансен

Если указатели не кажутся сразу интуитивными и полезными, их объяснили неправильно.
Джон Пурди

6

Как я действительно узнал об указателях? Написав простой компилятор первокурсников год колледжа.

Как объяснить указатели с точки зрения непрофессионала? Мне нравится (датированная?) Аналогия библиотечного каталога, хранящегося на карточках. Каждая карточка («указатель») содержит информацию о том, где находится какая-то книга («данные»), но на самом деле сама книга не содержит. Если вы изменяете карту («арифметика указателей»), все, что она делает, это изменяет книгу, на которую она указывает, и не влияет на саму книгу - просто будьте осторожны, чтобы не испортить адрес, иначе вы можете указать на несуществующую книгу или даже не та библиотека. Однако, если вы будете следовать «адресу» на карточке и перейдете к нужной части библиотеки («разыменовать указатель»), вы сможете просмотреть / изменить саму книгу.


+1 за память о моем курсе CS, где у меня было именно это объяснение
Гари Роу

В каком-то смысле это хорошо, но несколько вводит в заблуждение, поскольку на картах фактически не указано, где находится книга. Вам все еще нужно выполнить алгоритм поиска, ориентированный на тапки. Возможно, это лучше моделирует базу данных - ссылаясь на сохраненный объект по ключу (номеру вызова).
ДаренВ

+1 Аналогия с той же концепцией, которая была объяснена Barfieldmv, но с более реальной практикой.
Картик Сринивасан

5

Я предполагаю, что кто-то, изучающий указатели, знает, что такое обычные переменные и как они работают в C. Теперь давайте попробуем определить указатели с некоторыми из его атрибутов.

  • Они тоже переменные, но разной природы. Предположим, что в пространстве переменных есть два слоя. Нормальные переменные разных типов находятся в верхнем слое и указатели в нижнем слое. Как эта фигура

    альтернативный текст

  • Как следует из названия «Указатель», указатели могут указывать на что-то. Как наш палец может указывать на какой-то объект. На что они указывают? Это нормальные переменные. Короче говоря, «Указатели указывают на нормальные переменные».

  • Как и обычные переменные, указатели также имеют одинаковое количество типов, таких как int, char или float. И указатель определенного типа может указывать только на переменные того же типа.
  • Указатель может указывать на одну переменную, а затем тот же указатель может указывать на другую переменную. Просто тип должен быть таким же. Таким образом, связь указателя с некоторой переменной не является постоянной и может быть изменена.
  • Итак, как указатель объявлен? Почти как обычные переменные. Перед именем нужно поставить звездочку ( *). Подобно-

    int *pointer;
    
  • Тогда, как указатель связан с переменной? Использование &оператора перед переменной, как это утверждение

    pointer = &variable;
    
  • Как указатель используется, указывая на переменную? Это также можно сделать, поставив перед именем звездочку ( *). Затем его можно использовать вместо переменной, на которую он указывает

    *pointer = var1 + var2;
    

    вместо

    variable = var1 + var2;
    
  • Теперь поиграйте с указателями с некоторым кодом. Просто привыкните к этой характеристике указателей сейчас. До этого момента мы говорим о том, что делают указатели. Как только вы освоитесь, начните изучать, как указатели указывают на некоторую переменную и как они реагируют, если к ним применяются обычные арифметические операции. Затем перейдите к связи между указателями и массивами и указателями на указатели.

Это все, что я предлагаю по поводу изучения указателей.


Я хотел следовать процессу «сначала то, что он делает, то как». Абстракция!
Гульшан

5

Отредактировано в поддержку пересмотренного требования вопроса

Мой путь к пониманию «пост-указатель» (если я правильно помню) пошел следующим образом. У меня был некоторый простой опыт программирования на ассемблере, когда я еще играл с BBC Micro, поэтому у меня была концепция памяти в виде набора блоков (см. Ниже). Это было подкреплено использованием массивов. Тем не менее, я собирался в мир C и должен был иметь дело со строками, а это означало указатели. В BASIC это было тривиально, в ассемблере мне никогда не приходилось с ними работать, а теперь в классическом C это все указатели и прочее. Ах, но я могу вернуться к массивам с (завершенными нулем) строками так:

char s[] = "Hello, world!";
printf("%s",s);

Все хорошо, это просто массив символов (8 бит на символ в моем маленьком мире) с нулевым символом в конце, чтобы показать, где он заканчивается. Printf просто берет этот массив и запускает его, печатая. Но что, если я хочу передать эту строку в функцию?

void print_str(char* p) {
  printf("%s",p);
}

О чем говорится в руководстве, но о чем это все? Хм, char * означает «указатель на символ». ОК ... потерял меня. Затем до меня дошло, что char * делает p эквивалентным s [0]. Хорошо, я могу использовать это, но я все еще не понял, что это за указатели. Я имею в виду, как я могу установить некоторые данные с одной из этих вещей? Снова к руководству ...

char* p = "Hello World!";

Когда я пишу выше, я говорю себе: «объявите указатель на символ и установите его равным этому массиву символов». Каким-то образом этот указатель устраняет необходимость в массиве. Думаю, это компилятор, делающий что-то для меня. Так как я могу изменить массив с этим указателем? Я знаю, что я мог бы использовать версию массива

 s[2] = 'L'; 

но что эквивалентно в «указатель говорят»? Снова к этому руководству ...

*(p+2) = 'L';

Я предполагаю, что * просто означает «содержимое адреса памяти» и (p+2)есть s[2]. Что означало, что указатель p был ... просто ... адресом ... бонгом!

Что есть звук просветления. Я внезапно щелкнул указателями (это было очень давно, мы, старожилы, не «ухмылялись» до позднего времени). Это было просто косвенное.


Оригинал:

ОК, мой 2с стоит:

Представьте, что память - это куча коробок. Каждое поле имеет номер на стороне (адрес). Каждая коробка содержит номер (содержимое). Вы можете работать с этими блоками двумя способами: переменные (мне нужно содержимое блока N), указатели (мне нужно содержимое блока, которое находится в блоке N ). Указатели просто косвенные.

И для большого ответа, который охватывает все, что вам когда-либо нужно будет знать - прочитайте это .


++ Это более или менее так, как я преподавал предмет.
Майк Данлавей

Отредактированная статья для поддержки требований ОП.
Гари Роу

Какое руководство вы использовали, чтобы добавить дополнительные NUL-символы в конце ваших строк?
Роб Гиллиам

@raimesh Очень старый (около 1991 года). Не могу вспомнить что.
Гари Роу

1991? Это не старо для руководства по языку C - 1-е издание K & R было опубликовано в 1978 году! Просто заинтриговал, что когда-либо существовало руководство, в котором предлагалось ставить \ 0 в конце ваших строковых констант. (На самом деле, глядя на это снова, вы хотели поставить \ n?)
Роб Гиллиам

4

Возьми несколько маленьких кусочков дерева.

добавьте металлические крючки к одному концу и металлические глазки к другому.

Теперь вы можете сделать связанный список в материале, с которым вы можете играть.

Попробуйте объяснить с помощью этой физической опоры. Мне часто хотелось, чтобы у меня было это, когда я учил студентов-первокурсников.

Маленький металлический крючок - это указатель, а деревянная глыба - на что указывает вещь.

Я защищаю любого, чтобы не получить его после игры с блоками.


4

Я сделал мою жизнь проще, когда я просто удалил весь пух и начал рассматривать указатель как любую другую переменную, а не какую-то магическую сущность (давным-давно в 11 классе) ... просто знаю 3 вещи:

  1. Указатель - это переменная, в которой хранится адрес другой переменной (или просто любого адреса).
  2. * используется для получения значения в ячейке памяти, которая хранится в переменной указателя.
  3. Оператор & дает адрес ячейки памяти.

Все остальное - синтаксический сахар и здравый смысл. Просто напишите несколько простых программ на C (например, реализацию библиотеки связанных списков), используя указатели, чтобы освоить их.


2
  1. Указатель можно рассматривать как обобщение индекса в массив.
    • Учтите, что большой массив можно разделить на несколько меньших неперекрывающихся массивов переменного размера. Теперь эти меньшие массивы - это то, что мы обычно называем массивом. Чем больше, тем все пространство памяти компьютера. Процесс отсечения меньших массивов называется выделением памяти.
  2. Набор структур, которые связаны между собой некоторыми указателями, можно рассматривать как ориентированный граф .
    • Каждая вершина является переменной, которая может содержать некоторое значение.
    • Некоторые переменные являются указателями, и каждый указатель может иметь ровно один исходящий фронт на что-то другое.
    • Переменные, которые не являются указателями, не будут иметь какого-либо исходящего преимущества. Они могут иметь любое количество входящего фронта.

2

Я не могу вспомнить обстоятельства, связанные с моими указателями, ага, но я задним числом восстановил воспоминания о моем понимании массива в стиле c. (т.е. arr[3]такой же как *(arr+3))

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


2

В основном @Gary Rowe представил правильную модель. Память как набор ящиков с адресами (номерами) на них. В каждом поле хранится значение (число).

Идея указателя состоит в том, чтобы интерпретировать значение в одном блоке как адрес другого блока. Это значение используется для ссылки на конкретное поле, поэтому оно называется ссылкой . Таким образом, разыменование - это процесс открытия окна, на которое ссылаются.

если vэто переменная (блок), то оператор

  • vозначает ценность v, т.е. дай мне то, что находится в коробке
  • *vозначает разыменование значения v, т. е. дать мне то, что находится в поле, на которое ссылается значениеv
  • &vзначит ссылка v, т.е. дай мне адрес на коробке

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

Указатели - это вопрос интерпретации. Я думаю, что объяснение делает вещи намного проще. Арифметика указателей - чрезвычайно простые и интуитивно понятные операции, если показать простой пример с памятью из 10 переменных.


2

Объяснение, которое я действительно взломал, было:

Рассмотрим городскую сетку с разными домами, построенными на участках земли. В вашей руке вы держите лист бумаги. На бумаге вы написали:


Дом Давида,

112 Так и так улица.


Кусок бумаги (переменная указателя) содержит адрес, который указывает на дом Дэвида. Когда вы хотите сказать другу, чтобы он посмотрел на классный дом Дэвида, гораздо проще использовать лист бумаги в качестве ссылки на дом, чем отправлять двухэтажное здание по почте.

Как и в случае с реальными указателями, вы можете столкнуться с некоторыми проблемами, следуя адресу, указанному на листе бумаги. Дэвид мог бы переехать, и когда вы туда доберетесь, вы просто найдете большую дыру в земле. В этом случае было бы лучше стереть адрес на бумаге, когда Дэвид переехал, или хотя бы сменить его на новый. Вы также можете обнаружить, что идете по адресу и входите в то, что, по вашему мнению, является гостиной вашего друга Дэвида, но на этот раз вы попадаете в совершенно незнакомый бассейн. Кто-то использовал пространство по адресу, который вы имели, для чего-то совершенно другого.


2

Если вы хотите объяснить указатели, вы должны сначала объяснить память. Я обычно делаю это, используя миллиметровку / прямоугольную бумагу со строками и столбцами. Если «ученик» понимает память, он может понять, что такое адрес. Если у вас есть адрес, у вас есть указатели.

Вы можете играть с этой абстракцией. Например, напишите адрес (номер) одного квадрата в другой квадрат. Теперь нарисуйте стрелку от квадрата указателя до квадрата назначения. Теперь перезапишите указатель (например, увеличьте его) и отрегулируйте стрелку. Запишите адрес в другой квадрат и позвольте ученику нарисовать стрелку ...

Следующий шаг: присвойте определенным квадратам (например, указателю) имя. Теперь вы можете объяснить разыменование. Вот и все.


2
Напоминает мне «компьютер», которым я пользовался до того, как я смог достать тот, на котором действительно использовались электроны - картон «CARDIAC», я думаю, он назывался. Буквально, писать числа в пронумерованных коробках, чтобы получить числа из других пронумерованных коробок. Это было образовательно, и у меня никогда не было проблем с пониманием указателей на настоящие микропроцессоры.
ДаренВ

2

Возможно, это только я, но я хорошо работаю с аналогиями. Допустим, у вас есть друг (функция / класс) "Foo", который хочет, чтобы кто-то другой (другая функция / класс), "Бар", связался с вами по какой-то причине. «Foo» может заставить вас пойти посмотреть «Бар», но это не удобно, перемещая все эти существа (экземпляры) вокруг. Однако «Foo» может отправить «Бар» ваш номер телефона (указатель). Таким образом, независимо от того, где вы находитесь, «Foo» знает, как связаться с вами, не находя вас.

И, скажем, у «Бар» есть знакомый «Баз», который тоже хочет с вами связаться. Но вы защищаете свой номер телефона и не хотите, чтобы все имели, «Баз» может позвонить «Бар» (телефон в качестве указателя), который затем может переадресовать вам (другой указатель). И так далее, и далее по цепочке друзей «Баз» и друзей друзей.


2

Указатели сделать путем больше смысла , если вы изучали язык ассемблера и / или компьютерную архитектуру. Я думаю, что если бы я преподавал класс C, я бы начал с пары недель архитектуры, чтобы объяснить модель памяти и виды инструкций, которые фактически выполняет процессор.


Абсолютно. Когда вы имеете дело с регистрами и понимаете такие вещи, как непосредственные значения и косвенные адресации, вся концепция указателей интуитивно понятна. Я выучил сборку 6502, а затем сборку 68K, прежде чем писать свою первую строку на C, поэтому к тому времени, когда я познакомился с указателями, я посмотрел на (промежуточную) сборку компилятора, и она была именно такой, как и ожидалось.
Радиан

2

Мое "ага!" Настал момент в этом уроке:

Учебник по указателям и массивам в C

Чтобы быть точным, это пришло в этой главе: Глава 3: Указатели и строки

Чтобы быть еще более точным, это пришло с этим предложением:

Параметр, передаваемый в put (), является указателем, то есть значением указателя (поскольку все параметры в C передаются по значению), а значением указателя является адрес, на который он указывает, или, просто, адрес ,

Когда я прочитал это, облака разошлись, и ангелы взорвали трубные фанфары.

Ведь каждый учебник или книга по Си, которые я читал до этого, утверждали, что Си может передать по значению или по ссылке гнусную ложь. Правда в том, что C всегда передается по значению, но иногда передаваемое значение бывает адресом. Внутри метода создается копия этого адреса, точно так же, как создается копия переданного типа int. Копия не создается из значения, на которое указывает указатель. Таким образом, используя указатель внутри метода, вы можете получить доступ к исходному значению и изменить его.

Я никогда не становился программистом C, но я стал программистом .NET, и объекты и ссылки на объекты работают одинаково; ссылка на объект передается по значению (и, следовательно, копируется), но сам объект не копируется. Я работал со многими программистами, которые не понимают этого, потому что они никогда не изучали указатели.


1

Хитрость заключается в том, чтобы объяснить, что местоположение вещи и сама вещь не одно и то же, точно так же, как изображение трубы - это не труба . Когда вы перемещаете вещь, ее местоположение меняется. Место остается, и кое-что еще можно положить туда.


1

Указатель - это заметка, которая говорит вам, где что-то полезное. Он содержит местоположение вещи и говорит вам, насколько она велика (во всяком случае, в C). Таким образом, двойной указатель похож на заметку с надписью «В холодильнике шесть упаковок». Вы должны пойти за шестью пачками, чтобы выяснить, кола это или Budweiser.


1

Учитывая код:

int v=42; // объявляем и инициализируем простую переменную

int *p = &v; // создаем точку p для переменной v

О вышеприведенном коде можно сказать следующее:

int * p // "указатель int p" ... так вы объявляете указатель на переменную типа int

*p // "указывает на p" ... это данные, на которые указывает p, то же самое, что и v.

&v // "адрес переменной v" ... это представляет буквальное значение для p


1

http://cslibrary.stanford.edu/

На этом сайте есть отличные учебники для изучения указателей и управления памятью.

Я бы посоветовал вам пройтись по основам указателей, указателям и памяти, приведенным на сайте. Вы также можете посмотреть на проблемы со связанными списками, приведенными по ссылке, чтобы еще больше усилить концепцию указателей.


1

Ключ к объяснению указателей - убедиться, что люди, которым вы объясняете, уже понимают концепцию памяти. Хотя было бы неплохо, если бы они действительно поняли его на низком уровне, полагая, что память существует как массивный массив, и понимания того, что вы можете получить доступ к любой позиции в массиве по ее местоположению индекса, достаточно.

Следующий шаг, имеющий концепцию передачи местоположения индекса, а не копирования всей памяти, имеет смысл для большинства людей. И этого достаточно, чтобы позволить большинству людей понять, почему указатели полезны.

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

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

После того, как кто-то понял указатели, следующая вещь, которую он должен понять, это разница между кучей памяти и памятью стека, и почему указатели на память стека опасны, когда передаются вне метода.


0

Я помню книгу «С загадки» или похожую, которую я прочитал просто потому, что это была одна из немногих книг по программированию / компьютерам, доступных в библиотеке, мое понимание С было зачаточным. Он бросил в вас C-выражение и попросил объяснить это, становясь все более и более сложным.


0

Когда я учился в университете, у моего профессора были действительно аккуратные слайды PowerPoint, изображающие точку как отдельную переменную со стрелкой в ​​ячейке памяти (представленной в виде массива), и когда мы делали связанные списки, он делал это шаг шаг за шагом, показывающий, когда стрелка меняется, когда указатель разыменовывается и т. д., никто не мог этого понять в течение пары минут. Сама концепция действительно проста, но правильное выполнение или применение в практических программах требует больше практики.


0

Прежде чем я это сделаю, я объясню, что в программировании «все использует память» и (статическое) распределение переменных в памяти. Я также объясню, что такое адрес памяти и связь между пространством памяти, адресом памяти и переменными.

Наконец, я объясняю, что существуют целочисленный тип данных и переменные, строковый тип данных и переменные ... и так далее, пока не объясним, что существует специальный тип данных, который хранит адреса памяти, который имеет пустое значение, например 0 o "", называется ноль .

И, наконец, динамически распределяемые переменные посредством использования указателей.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.