Яка різниця між змінними та покажчиками?


10

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

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

Чому це відрізняється від змінної? Змінні - це символьні назви адрес пам'яті, а компілятори замінять ім'я фактичною адресою. Це означає, що змінні містять посилання на місця пам'яті і можуть вважатися вказівками на дані за цією адресою, якщо такі дані існують.

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

Що я тут пропускаю?


4
Нічого, покажчик - це фактично тип, семантична інтерпретація якого полягає в тому, що вміст змінної є адресою. Зверніть увагу, що є дві адреси, там адреса вказівника (тобто, де зберігається змінна) та адреса, на яку вказує посилання (фактичні дані за адресою змінної). Вказівник - це тип посилання .
Люк Матхісон

Відповіді:


8

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

По-перше, ваше твердження Variables are symbolic names for memory addresses, це майже коректно, але заплутує концепцію та її звичайну реалізацію. Змінна - це фактично лише контейнер, який може містити значення, яке можна змінити. Зазвичай цей контейнер реалізований на комп'ютері як сукупність простору пам'яті, що характеризується адресою та розміром, оскільки змінні можуть містити об'єкт, який потребує представлень з більшою чи меншою кількістю інформації.

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

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

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

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

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

Отже, ще одна важлива концепція - це ідентифікатори та іменування. Іменування сутності (значення) може бути здійснено шляхом асоціації ідентифікатора зі значенням (як правило, в декларації). Але значення також можна отримати, застосувавши операції до інших названих значень. Імена можна повторно використовувати, і існують правила (правила визначення) для визначення того, що асоціюється з даним ідентифікатором, відповідно до контексту використання. Існують також спеціальні імена, що називаються litterals, для назви значень деяких доменів, таких як цілі числа (наприклад, ) або булеві (наприклад, true ).612

Асоціація незмінного значення з ідентифікатором зазвичай називається константою. Літтерали - константи в цьому сенсі.

"Контейнери цінностей" також можна вважати значеннями, а їх зв'язок з ідентифікатором є змінною у звичайному "наївному" розумінні, яке ви використовували. Тож ви можете сказати, що змінна є "константою контейнера".

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

Власне, призначення - це смислові операції, які динамічно відбуваються під час виконання програми, тоді як декларації мають більш синтаксичну природу і зазвичай повинні інтерпретуватися в тексті програми незалежно від виконання. Ось чому статичне обстеження (тобто текстове скопіювання) зазвичай є природним способом зрозуміти значення ідентифікаторів.

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

Щодо коду, ви заявляєте [pointers] might indicate the entry point to a section of code and can be used to call that code. Насправді це не зовсім так. Розділ коду часто безглуздо поодинці (з точки зору високого рівня чи реалізації). З точки зору високого рівня, код зазвичай містить ідентифікатори, і вам доведеться інтерпретувати ці ідентифікатори в статичному контексті, де вони були оголошені. Але насправді можливе дублювання того ж статичного контексту, по суті, через рекурсію, яка є динамічним явищем (час виконання), і код може бути виконаний лише у відповідному динамічному екземплярі статичного контексту. Це трохи складно, але наслідком цього є те, що правильна концепція - це закриття, яке пов'язує фрагмент коду та оточення, де слід інтерпретувати ідентифікатори. Закриття є належним смисловим поняттям, тобто є правильно визначеним смисловим значенням. Тоді ви можете мати константи закриття, змінні закриття,

Функція - це закриття, як правило, з деякими параметрами для визначення або ініціалізації деяких його сутностей (констант і змінних).

Я пропускаю безліч варіантів використання цих механізмів.

Замикання можна використовувати для визначення структур ОО в імперативних або функціональних мовах. Насправді, рання робота над стилем OO (можливо, перед назвою) робилася саме так.

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

Але пам’ятайте: багато речей перебуває в очах глядача, доки він зберігає послідовний погляд. Точки зору можуть відрізнятися.

Чи відповідає це на ваше запитання?

PS: Це довга відповідь. Якщо ви вважаєте якусь частину її неадекватною, будь ласка, поясніть, про що йдеться. Дякую.


Мені довелося прочитати це кілька разів, але я думаю, що це відповідає на моє питання, так. Хоча мої визначення занадто орієнтовані на реалізацію, уявлення про те, що вказівник є певним типом змінної, здається точним, тобто "значення вказівника - це лише інша назва контейнера, а змінна вказівника - змінна контейнера" Де я не Ви отримаєте відмінність між вказівником, що містить адресу блоку коду, і контейнером, який містить контейнер, який містить закриття. Чи є різниця між статичним контекстом та програмою, що виконується?
NectarSoft

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

1
@NectarSoft (продовження) Отже, значення закриття - це асоціація фрагмента коду та динамічний екземпляр статичного контексту, який надає значення цьому фрагменту. Асоціація одного і того ж фрагмента коду з різним динамічним екземпляром одного і того ж статичного контексту дає різне закриття. Як правило, ваш код може використовувати змінну, що належить до цього контексту, але це буде різною змінною для кожного динамічного екземпляра контексту, хоча його ім'я (статично визначене) залишається тим самим. Чи пояснює це питання, чи я повинен будувати приклад у відповіді (формат коментарів обмежений)?
babou

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

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

2

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

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