Яке приємне пояснення для покажчиків? [зачинено]


72

У ваших власних дослідженнях (самостійно чи в класі) у вас був момент "ах-ха", коли ви, нарешті, справді зрозуміли вказівники? Чи є у вас пояснення, яке ви використовуєте для початківців програмістів, яке здається особливо ефективним?

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

Іншими словами, що було потрібно для розуміння значення &s та *, коли ви могли з упевненістю їх використовувати? Вивчення синтаксису та термінології або випадків використання недостатньо, в якийсь момент ідею потрібно інтерналізувати.


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

Наприклад:

Я лише дещо зрозумів вказівники синтаксично в C. Я почув двох моїх друзів, які пояснювали вказівники іншому другові, який запитав, чому structбуло передано покажчик. Перший друг розповів про те, як його потрібно посилати та змінювати, але це був лише короткий коментар другого друга, де він мене вдарив: "Це також ефективніше". Пропуск 4-х байтів замість 16-ти байт був останньою необхідною концептуальною зміною.


16
Метод «дробовика»: кидайте * s скрізь, поки це не працює.
Майкл К

15
@Michael: Так, удачі в цьому.
Роберт Харві

8
Це запитання виникає невдовзі після початку кожного семестру ЗП. Останнє втілення тут: stackoverflow.com/questions/4118647/…
Tim Post

10
Яке приємне пояснення для покажчиків? Брайан Керхіган і Денніс Річі ненавидять інженерів програмного забезпечення.
Адам Кросленд

3
Він "клацнув" для мене після того, як провів деякий час одномоментний машинний код у відладчику. Так, я був знайомий з основами комп'ютерної архітектури - я навчився складанням на Commodore 64, і x86 ASM після цього була досить простою. Тому я вже знав поняття "адреса", я просто не розумів, як воно відображається на синтаксичні конструкції С.
zvrba

Відповіді:


25

Діаграма пам'яті як а-сітка

Зазвичай те, що я роблю, представляє пам'ять як "сітку", щоб я міг складати адреси, виділяти різні простори пам'яті і записувати в комірки значення (або навіть далі, їх двійкові уявлення) і прив'язувати покажчики в пам'яті до значень, які вони Справа в. (А потім ще згадати, що це спрощення).

Зазвичай для більшості моїх учнів це "ооооо".

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

Тоді, коли мова йде про те, щоб вони перестали забувати, як використовувати & і *, це дуже просто: представіть це так само, як вони роблять математичні чи фізичні обчислення. Якщо поділити відстань у км на час на годину, ви отримаєте швидкість в км / год. Що потрібно, щоб вийти. Простий.

printf до Порятунку

Виконання лише декількох основних прикладів, які візуально представляють те, що ви пояснили з ними, втішать їх у тому, що вони думають, що вони зрозуміли, або дадуть їм можливість сказати "ах, я цього не розумію".

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

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

Потім починайте арифметику вказівника.


Додаток: Рекурсія

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

Зазвичай є "що ...?" Миттєво, і коли ви додасте ще один параметр до свого printf для друку числових значень та відступу кроків, це стає полегшенням зітхання.


Альтернативи: Модель Play-Doh та чашки для води

У мене фактично були співробітники в університеті, які показали студентам відео, що пояснювали покажчики та доступ до пам’яті за допомогою пасти play-doh. Це було неймовірно розумно і добре зроблено, хоча я ніколи насправді не використовував цю техніку сам, за винятком дуже молодих учнів, зацікавлених у розумінні програмування (але зазвичай тих, кого я не вела б до мови за допомогою покажчиків занадто рано). В основному, використовуючи крихітні кульки play-doh, які ви можете приєднати до інших більших кульок play-doh, що представляють простори пам’яті, і які ви можете комбінувати, щоб або зв’язати їх (як у пов'язаній структурі даних), або об'єднатись разом (як у суміжних простір пам'яті). Використання різних кольорів для вказуваного простору пам'яті та покажчиків також допомагає. Але я все ще думаю, що річ "Пам'ять як сітка" працює краще, як ви можете чітко показати, що вказівка ​​насправді є справою "адресації", як на "карті / сітці". Тоді як режим Play-doh все ще заплутує їх у думці, що речі дійсно "торкаються" одне одного в пам'яті.

Річ з водою в чашці води використовувалася також безпосередньо колегою, але я не знаю, чи придумала вона це. Це був цікавий підхід, але я помітив, що багато студентів були спантеличені поясненням. Щось схоже на техніку чашки кави DevSolo . Але я думаю, що це насправді вводить в оману, коли ви змушуєте студентів плутати контейнери, структури даних, покажчики та масиви. Я можу бути цікавим підходом до пояснення масивів на початку, я припускаю, але я б не дотримувався цього дуже довго.


Нічого, дякую за щедроту. Радий, що відповідь була оцінена.
haylem

Накресліть: | це звучить як якесь гарне вчення!
Spooks

80

Хтось набагато мудріший, ніж я колись сказав:

Монахиня Ву Цзінканг запитала шостого патріаха Хуйненга: "Я багато років вивчала сутру Махапарінірвана, але є багато областей, які я не зовсім розумію. Будь ласка, просвіти мене".

Патріарх відповів: "Я неграмотний. Будь ласка, прочитайте мені персонажів, і, можливо, я зможу пояснити значення".

- сказала монахиня, "Ви навіть не можете розпізнати персонажів. Як ви тоді зможете зрозуміти значення?"

"Істина не має нічого спільного зі словами. Істину можна уподібнити до яскравого місяця на небі. Слова в цьому випадку можна уподібнити пальцю. Палець може вказувати на розташування Місяця. Однак палець не є Місяць. Щоб подивитися на місяць, треба дивитись за палець, правда? "


13
+1 для перенаправлення місяця. +1 за коан, якщо я міг.
Тім Пост

14
Який звук викликає один палець?
Адам Кросленд

3
@Адам, це залежить від того, використовуєте ви мишку чи трекпад.
Даніель Йосиф

7
@Frank Це була ВЕЛИКА цитата. Я все ж думаю, що це не допоможе втілити цю ідею. Спеціально для когось нового для покажчиків.
Гульшан

11
Це прекрасна історія ... але я підозрюю, що люди голосують саме через це, а не тому, що це добре пояснює покажчики.
Kyralessa

46

Я виявив, що діаграми дуже корисні. Приклад:

діаграма вказівника


Така діаграма допомогла мені побачити, що вказівники були власною змінною, але містили значення, яке було розташуванням іншого об'єкта, тобто масиву чи рядка. Також, закінчивши олівцем, я міг би використовувати його для відстеження своєї програми на папері або на дошці / дошці.


4
Або значення в межах "вказівника" має бути 4, або індекси масиву (або адреси пам'яті) повинні починатися з 0. В іншому випадку, як покажчик, який містить значення 3, вказує на місце 4?
МАК

++ Саме так я збирався пояснити це. Я стартував у Fortran (для кращого чи гіршого!). У Fortran, тоді, ми використовували паралельні масиви замість масивів структур (не таке, як нове ). Якщо один масив містив в масиві індекс "іншого рядка", ми називали його "покажчиком", і це було захоплююче. Ми склали пов’язані списки, дерева, ви його називаєте.
Майк Данлаве

2
Я вважаю, що вказівники найкраще пояснюються за допомогою зображень із зазначенням того, що зберігається куди, та стрілок, щоб вказати, куди вказують вказівники.
габлін

32

Коли я вперше "дізнався" про вказівники, я начебто наштовхнувся на це. Мій університет прийняв рішення задовго до того, як я записався зосередити навчальну програму навколо Java, тому коли мій професор із структур даних прочитав одну лекцію на С та попросив нас застосувати XOR-список із вказівниками, я відчув, що я щось добираюся шлях над моєю головою.

Я зрозумів визначення:

Покажчик - це змінна, яка містить адресу змінної

Але я все ще не зрозумів значної частини концепції. Озираючись назад, я думаю, що це зосереджено на трьох речах:

  1. Що саме є пам'яттю? (У той час я не брав клас з організації комп'ютерних організацій)

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

  3. Як саме вигідно зберігати адресу змінної, а не просто використовувати змінну?

Тільки до того, як я придбав книгу K&R і не вирішив усіх проблем, я справді зрозумів покажчики. Окрім того, що я давно закінчив клас «Комп’ютерна організація» (що, на мою, потрібно вимагати до вивчення 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. Розшифровка ієрогліфів, розмовно відома як "визначення вказівника"

Отже, загалом, я думаю, що при вивченні покажчиків повинно бути принаймні 3 "ага" моменти. Я все ще студент, тому я подумав, що ви оціните точку зору того, хто ще (відносно) свіжий вивчає цю концепцію.


+1 для 3 "А-ха!" монети. Виробництво покажчиків буває шарами. Я "розумів" бали давно, перш ніж зрозумів, що лише приблизно наполовину зрозумів покажчики на покажчики :)
Бінарний Більш занепокоєний

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

Погодився, @Benjol. Я здивований, що синтаксис int* ipзустрічається не так часто. Я нарешті почав розуміти покажчики, як тільки побачив код, який був відформатований так. Тоді я міг би прочитати це як "ip є тип int pointer".
Яків

19

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

Я завжди пояснюю роботу цього простим створенням txt-файлу на робочому столі та двома ярликами до файлу. Після копіювання та видалення ярликів ви можете зрозуміти, що люди розуміють ідею "посилань".

Як тільки група зрозуміє основні елементи ярликів, ви можете почати пояснення покажчиків у будь-якому разі. Вони, мабуть, зрозуміють це досить легко.


Це не погана аналогія. Лише кілька пунктів, які потрібно додати для тих, хто приймає цю буквально «жорстку посилання», завжди вказуватиме на її ціль, навіть якщо вона змінює каталоги, вказівник вказуватиме на оригінальну пам’ять, навіть якщо об’єкт переміщений. "Жорстке посилання" підкаже вам, коли цілі більше не існує, звисаючий покажчик покажчика повинен бути встановлений на NULL.
snmcdonald

Жорстке посилання схоже на відлічений розумний покажчик
jk.

1
+1. Одна з найкращих практичних аналогій для пояснення покажчиків. Я впевнений, що студенти зрозуміють цю ідею негайно, оскільки ця функціональність найбільш часто використовується всіма.
Karthik Sreenivasan

13

8-10 років тому я викладала вступний курс "С" в коледжі громади. Це завжди було цікавою темою для вивчення. Те, що, здавалося, найкраще працює, і це було після того, як кілька разів обговорили співпрацівниці, - це скористатися чашкою кави та рукою.

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

Близька рука була нульовою, палець вказував на мою голову (мов пістолет-макет) - звисаючий вказівник.

Тоді з кількома демонстраціями та прогулянками через налагоджувач він клікнув найбільше.


3
Ви вже мене переплутали.
kirk.burleson

1
@Kirk, як так? дозвольте мені побачити, чи можу я це очистити.
DevSolo

4
++ Немає нічого подібного до навчання, щоб змусити думати про ці речі.
Майк Данлаве

Один із моїх викладачів в університеті зробив подібну справу, використовуючи студентів (один з яких був «Ніл», для додавання сміху) замість чашки кави. Вказівкою рукою на глядачів було звисаюче вказівник, бо воно могло вказувати на що завгодно.
Kaz Dragon

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

10

Я дійсно дуже хвилююся, коли чую питання "як ти зрозумів вказівки". Я завжди вважав, що концепція неймовірно проста, і логічна еволюція мов забезпечує велику силу програмістам.

Мене хвилює те, що мені ніколи не було важко зрозуміти поняття покажчиків. Отже, коли ви тут "коли ти нарешті отримав це" знову і знову, починаєш думати:

Я насправді це отримую? Може, я ніколи цього не робив?

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

Просто кидаючи ту ідею, звичайно, особисто я люблю гарну схему, і Стів Гібсон завжди робить фантастичну роботу з пояснення чого-небудь !


Цікаво ... якою мовою ви користувалися у той час? Я думаю, що синтаксис С подорожує багато людей. Якби ви вперше знали збірку, я міг би зрозуміти, що це одна з причин. [BTW, я хочу проголосувати за це, але сьогодні я дійшов до свого обмеження.]
Macneil

Що цікаво, я довго не знав "небезпечних" покажчиків, працюючи в Python (і Java в університеті). Тоді я взяв модуль "об'єктно-орієнтованих методів", який використовував C ++ як мову вибору, і туди прямо занурився.
Marcus Whybrow

Крім того, я думаю, що розуміння того, як програма представлена ​​в пам'яті, безумовно може допомогти, але я думаю, я вважаю за краще сказати, що розуміння того, чому покажчики були корисним доповненням до мови, є найбільш ефективним кутом зору, оскільки ви проходите те саме, хоча процес як оригінальні дизайнери.
Marcus Whybrow

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

Так, покажчики завжди були настільки очевидно простими і корисними, що я не можу уявити, думаючи, що в них є щось "важке". Я ненавиджу, коли викладач будь-якого курсу каже "зараз, це трохи хитро", тому що це просто так підривно. Просто навчіть прокляті речі, і нехай студенти самі вирішують, чи вважають вони це складним.
Джон Перді

7

У мене ніколи не було великих проблем з покажчиками на С, але це може бути тому, що мені довелося спочатку навчитися асемблеру. Насправді було полегшенням більше не потрібно керувати адресами. Тож, можливо, відповідь (якщо припустити, що ви це викладаєте) полягає в тому, щоб дати студентам наслідувати мову складання для роботи. Вони будуть з'ясувати це в процесі написання нічого складнішого , ніж «Привіт, світ.»


+1 для адаптації більш примітивної абстракції, а не для спроби використовувати аналогію.
Анонімний тип

У моїй середній школі один підрозділ Комп'ютерних досліджень був присвячений вивченню комп’ютера з сірниковою коробкою , який можна навчати з дошки, не торкаючись і не залучаючи справжнього комп’ютера.
rwong

@Larry Coleman, асамблея !!!!!!!!!!! Хочу спробувати спершу перед C. Скажіть, будь ласка, з чого почати вчитися. Безкоштовні електронні книги, безкоштовний PDF-файл? ІДЕ? Будь ласка !!!!!!!!!!!!!!!!!!!
Spacez Ly Wang

7

Покажчик - це змінна, значення якої - адреса пам'яті іншої змінної.


Елегантний, чому це ускладнюється.
Bjarke Freund-Hansen

Якщо вказівники не здаються інтуїтивно зрозумілими та корисними, їх пояснили неправильно.
Джон Перді

6

Як я насправді дізнався про покажчики? Написав простий компілятор першокурсників рік коледжу.

Як пояснити покажчики в умовах мирян? Мені подобається (датована?) Аналогія бібліотечного каталогу, що зберігається на індексах. Кожна картка ("покажчик") містить інформацію про те, де знаходиться якась книга ("дані"), але насправді не містить саму книгу. Якщо ви модифікуєте карту ("арифметику вказівника"), все, що вона робить, - це змінити книгу, на яку вона вказує, і не впливає на саму книгу - просто будьте обережні, щоб не закрутити адресу, або ви можете вказати на неіснуючу книгу або навіть неправильна бібліотека. Однак якщо ви дотримуєтеся "адреси" на картці та переходите до належної частини бібліотеки ("dereference the pointer"), ви можете побачити / змінити саму книгу.


+1 на згадку про мій курс CS, де я точно пояснив це
Gary Rowe

Це в чомусь добре, але дещо вводить в оману, оскільки картки насправді не говорять, де знаходиться книга. Ще потрібно виконати алгоритм пошуку, орієнтованого на кросівки. Можливо, це краще моделює базу даних - перенаправлення на збережений об'єкт за ключем (номер виклику).
DarenW

+1 Аналогія зберігає ту саму концепцію, яку пояснила Барфілдмв, але з більш реальним життєвим підходом.
Karthik Sreenivasan

5

Я припускаю, що хтось, хто збирається вивчати покажчики, знає, що таке нормальні змінні та як вони працюють у C. Тепер, спробуємо визначити покажчики з деякими його атрибутами,

  • Вони також є змінними, але різної природи. Припустимо, що у змінному просторі є два шари. Нормальні змінні різних типів знаходяться у верхньому шарі та вказівники на нижньому шарі. Як ця цифра-

    alt текст

  • Як випливає з назви "Покажчик", вказівники можуть вказувати на щось. Як і наш палець може вказувати на якийсь предмет. На які речі вони вказують? Це звичайні змінні. Коротше кажучи, "Покажчики вказують на нормальні змінні".

  • Як і звичайні змінні, вказівники також мають однакову кількість типів, наприклад, int, char або float. І вказівник конкретного типу може вказувати лише на змінні одного типу.
  • Вказівник може вказувати на одну змінну, а пізніше той самий вказівник може вказувати на іншу змінну. Просто тип повинен бути однаковим. Отже, асоціація вказівника з деякою змінною не є постійною і може бути змінена.
  • Отже, як оголошується покажчик? Майже як звичайні змінні. Ви повинні передувати імені зірочкою ( *). Подібно до-

    int *pointer;
    
  • Потім, як вказівник пов'язаний зі змінною? Використання &оператора перед змінною, як це твердження-

    pointer = &variable;
    
  • Як використовується вказівник, вказуючи на змінну? Це також робиться попереднім назвою зірочкою ( *). Тоді його можна використовувати замість змінної, на яку вказує зараз -

    *pointer = var1 + var2;
    

    замість

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

Це все, що я підкажу щодо вивчення покажчиків.


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

5

Відредаговано на підтримку переглянутої вимоги питання

Мій шлях до розуміння "пост-покажчика" (якщо я правильно пригадую) пройшов так. У мене був простий досвід програмування монтажу, коли я ще спілкувався з BBC Micro, тому в мене з'явилася концепція пам'яті як купа коробок (див. Нижче для цього). Це було підкріплено використанням масивів. Однак я збирався у світ C і мав справу з рядками, і це означало покажчики. У BASIC це було тривіально, в асемблері мені ніколи не доводилося працювати з ними, а зараз у класичному С - це все покажчики та інше. Ах, але я можу повернутися до масивів із (нульовим завершенням) рядками, як це:

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!";

Коли я пишу вище, я кажу собі "оголосити покажчик на знак char та встановити його рівним цьому масиву символів". Якось цей вказівник усуває необхідність масиву. Вгадайте, що компілятор робить якісь речі для мене на зміну. Тож як я можу змінити масив за допомогою цього вказівника? Я знаю, що я міг би використовувати версію масиву

 s[2] = 'L'; 

але який еквівалент у "покажчику вказівника"? Знову з цим посібником ...

*(p+2) = 'L';

Я припускаю, що * просто означає "вміст адреси пам'яті" і (p+2)є s[2]. Що означало, що вказівник р був ... просто ... адресою ... бонгом!

Що є звук просвіти. Я раптом покрутив покажчики (це було дуже давно, ми, старі таймери, не «гаркалися» до цього пізніше). Це було просто непряме.


Оригінал:

Гаразд, мій 2с варто:

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

А для великої відповіді, яка охоплює все, що вам колись потрібно буде знати - прочитайте це .


++ Це більш-менш те, як я викладав цю тему.
Майк Данлаве

Відредагована стаття для підтримки вимог ОП.
Гері Роу

У якому посібнику ви використовували додані додаткові символи NUL в кінці рядків?
Роб Гілліам

@raimesh Дуже стара (близько 1991 року). Не можу пригадати, який.
Гері Роу

1991? Це не є старим для посібника з мови С - перше видання 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", я думаю, це називалося. Буквально записуйте числа в нумеровані поля, щоб отримати числа з інших пронумерованих полів. Це було навчальним, і мені ніколи не було проблем із розумінням покажчиків на реальні мікропроцесори.
DarenW

2

Можливо, це лише я, але я добре працюю з аналогіями. Тож скажімо, у вас є друг (функція / клас) "Foo", який хоче, щоб хтось інший (інша функція / клас), "Bar", зв'язалися з вами чомусь. "Foo" може вас відвідати "Бар", але це не зручно, переміщаючи всіх цих істот (екземпляри). Однак "Foo" може надіслати "Bar" ваш номер телефону (вказівник). Таким чином, де б ви не знаходилися, "Foo" знає, як зв’язатися з вами без того, щоб вас знаходити.

І, скажімо, у "Бар" є знайомий "Баз", який теж хоче зв’язатися з вами. Але ви захищаєте свій номер телефону і не хочете, щоб усі мали його, "Баз" може зателефонувати в "Бар" (телефон як вказівник), який може потім переадресувати дзвінок вам (інший покажчик). І так далі, і далі по ланцюжку друзів "База" та друзів друзів.


2

Покажчики зробити шляхом більше сенсу , якщо ви вивчали мову асемблера і / або комп'ютерну архітектуру. Я думаю, що якщо я буду викладати клас C, я б почав з архіву архіву пару тижнів пояснювати модель пам’яті та види інструкцій, які процесор реально виконує.


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

2

Моє "ага!" Настав момент у цьому підручнику:

Навчальний посібник з покажчиків та масивів на С

Якщо бути точним, він прийшов у цій главі: Глава 3: Покажчики та рядки

Якщо бути ще більш точним, він прийшов із цим пропозицією:

Параметр, переданий put (), - це вказівник, тобто значення вказівника (оскільки всі параметри в C передаються за значенням), а значення вказівника - адреса, на яку він вказує, або, просто, адреса .

Коли я прочитав це, хмари розступилися, і ангели підірвали труби фанфарів.

Бо, бачите, кожен навчальний посібник чи книга, яку я прочитав до цього, стверджував, що С може передати цінність чи посилання - нечесну брехню. Правда полягає в тому, що C завжди передається за значенням, але іноді передане значення буває адресою. У межах методу копія робиться за цією адресою, подібно до того, як копія була б зроблена з переданого int. Копія не робиться з того значення, на яке вказує вказівник. Таким чином, використовуючи покажчик у межах методу, ви можете отримати доступ до вихідного значення та змінити його.

Я ніколи не став програмістом на C, але я став програмістом .NET, і об'єкти та посилання на об'єкти працюють однаково; посилання на об'єкт передається за значенням (і таким чином копіюється), але сам об'єкт не копіюється. Я працював навколо багатьох програмістів, які цього не розуміють, оскільки вони ніколи не вивчали покажчики.


1

Хитрість полягає в тому, щоб пояснити, що розташування речі та сама річ не однакові, як і зображення труби - це не труба . Коли ви переміщуєте річ, її місцезнаходження змінюється. Місце залишається, і там можна поставити якусь іншу річ.


1

Вказівник - це клейка примітка, яка повідомляє про те, де щось корисне. Він містить розташування речі і розповідає, наскільки річ велика (у С, в будь-якому випадку). Тож подвійний вказівник - це як наліпка, що говорить: «У холодильнику є шість пачок». Потрібно насправді дістати шість пакетів, щоб розібратися, чи це Кокс чи Будвайзер.


1

Дано код:

int v=42; // декларування та ініціалізація простої змінної

int *p = &v; // створення точки p до змінної v

Про вищезазначений код можна сказати наступне:

int * p // "int pointer p" ... саме так ви оголошуєте вказівник на змінну типу int

*p // "вказується на p" ... тобто ті дані, на які вказує p, їхні ж v.

&v // "адреса змінної v" ... це означає буквальне значення для p


1

http://cslibrary.stanford.edu/

На цьому сайті є чудові підручники для вивчення покажчиків та управління пам’яттю.

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


1

Ключовим моментом пояснення покажчиків є переконання, що люди, яким ви пояснюєте, вже мають розуміння концепції пам’яті. Хоча було б добре, якби вони насправді зрозуміли його низький рівень, вважаючи, що пам'ять існує як масивний масив, і розуміння того, що ви можете отримати доступ до будь-якої позиції в масиві за його індексним розташуванням, достатньо.

Наступний крок - концепція передачі місця розташування індексу, а не копіювання всієї пам'яті має сенс для більшості людей. І цього достатньо, щоб більшість людей могли зрозуміти, чому покажчики корисні.

Останнім кроком для розуміння покажчиків є пояснення, як ви можете передати як параметр розташування індексу пам'яті для методу зберігання місця розташування індексу, де зберігаються всі дані. Я виявив, що це може бути занадто далеко, щоб деякі люди могли впоратися.

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

Після того, як хтось схопив покажчики, наступне, що вони повинні швидко зрозуміти, - це різниця між накопичувальною пам’яттю та стеком пам’яті, і чому покажчики на стек пам’яті небезпечні, коли проходять поза методом.


0

Я пам’ятаю книгу «C пазли» або подібну, яку я читав чисто тому, що це була одна з небагатьох книг, що стосуються програмування / комп’ютера, наявних у бібліотеці, моє розуміння C було рудиментарним. Він кинув на вас експресиону С і попросив викласти його, ускладнюючись.


0

Коли я був в університеті, у мого професора було кілька дійсно акуратних слайдів Powerpoint, що зображували точку як окрему змінну самостійно зі стрілкою до місця пам’яті (представлене як масив), і коли ми робили пов'язані списки, він зробив би це крок - на крок, що показує, коли стрілка змінюється, коли вказівник відмежовується і т. д. ..., не було можливості зрозуміти це протягом пари хвилин. Сама концепція дійсно проста, але правильно робити або застосовувати її в практичних програмах потрібно більше практики.


0

Перш ніж це зробити, я пояснюю, що в програмуванні "все використовує пам'ять" і (статичне) переміщення змінної в пам'яті. Я також поясню, що таке адреса пам’яті та співвідношення між простором пам’яті, адресою пам’яті та змінними.

Нарешті, я пояснюю, що існують цілі типи даних і змінні, тип рядкових даних і змінні ... і так далі, поки не пояснюється, що існує спеціальний тип даних, який зберігає адреси пам'яті, який має порожнє значення, наприклад 0 o "", називається нульовим .

І, нарешті, динамічно розподілені змінні за допомогою використання покажчиків.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.