Я часто намагаюся бачити переваги покажчиків (крім програмування на низькому рівні).
Навіщо використовувати char * замість String або char [] або які переваги приносить арифметика вказівника.
То які плюси та випадки використання покажчиків?
Я часто намагаюся бачити переваги покажчиків (крім програмування на низькому рівні).
Навіщо використовувати char * замість String або char [] або які переваги приносить арифметика вказівника.
То які плюси та випадки використання покажчиків?
Відповіді:
Покажчики необхідні для динамічного розташування пам’яті, багатьох структур даних та ефективної обробки великої кількості даних. Без покажчиків вам доведеться розподіляти всі програмні дані в усьому світі або за функціями або еквівалентом, і ви б не зверталися, якби кількість даних зростала понад те, що ви спочатку дозволяли. Я не вагаюся використовувати тут абсолюти, але, наскільки я знаю, усі сучасні комп'ютерні мови мають вказівники в тій чи іншій формі.
У більшості мов, які використовують покажчики, є певні види посилань, які є покажчиками, і, можливо, певні види посилань, яких немає, і немає додаткової примітної різниці. cons
Осередок Ліспа - це пара покажчиків, хоча а fixnum
- не вказівник. У Java змінна, яка використовується для екземпляра класу, - це вказівник, але int
це не так. Синтаксис мови не відображає цього.
C незвично тим, що покажчики є необов'язковими, явними та дозволяють явну арифметику вказівника. Це абсолютно можливо записати struct foo bar; struct foo * baz;
, і як тільки ви виділили пам'ять, baz
ви можете використовувати як bar
і baz
представити struct foo
s. Оскільки вказівники необов’язкові, корисно мати нотаційні відмінності. (Це важливо в C ++ для розумних покажчиків, оскільки це дано boost::shared_ptr<foo> bar;
, bar.reset()
має одне значення і bar->reset()
, ймовірно, має набагато інше.)
(Насправді явні покажчики часто використовувались в інших мовах, коли C спочатку розроблявся, як, наприклад, ^
у Pascal. C - це більш давня мова, ніж більшість із поширених сьогодні, і це показує.)
Однією з цілей дизайну C було написати запис в Unix, і тому йому потрібно було детально обробляти місця пам'яті. (C насправді є однією з сімей мов впровадження системи, поширених під час його проектування. Іншим прикладом є Cybol для комп'ютерів з керуючими даними. C - той, що став великим хітом.) Отже, можна безпосередньо маніпулювати C покажчиками, призначення адрес пам'яті та обчислення нових. Це також призвело до деяких дизайнерських рішень в масивах C. C ґрунтується в значній мірі на арифметиці вказівника, і дійсно масив перетворюється на покажчик у дуже багатьох ситуаціях. Передача змінних функціям C за посиланням здійснюється покажчиком. Не було гострої потреби в масивах та передачі змінних за посиланням у тому вигляді, який мали інші сучасні мови, тому C не отримав їх.
Отже, відповідь полягає в тому, що в більшості мов нині ви постійно використовуєте покажчики, не нагадуючи про це. У мові C, і меншою мірою C ++, ви використовуєте вказівники або для того, щоб робити речі низького рівня, або виконувати речі вищого рівня, для яких немає спеціальних позначень.
Складні структури даних. Ви не можете створити щось на зразок пов’язаного списку чи двійкового дерева без покажчиків.
Немає "плюсів" і "мінусів" покажчиків. Вони просто інструмент, як молоток.
Посилання на C ++, Java та інших мовах такого ж типу - лише "безпечні покажчики". І ці посилання багато використовуються на Java.
NULL
, і вони не можуть бути змінені після їх створення.
Практично будь-якій комп'ютерній програмі потрібно перевіряти та змінювати значення в пам'яті (відомі як зазирвання та ковзання, для тих із нас, хто досить старий). Вам потрібно контролювати, де в пам'яті знаходяться ці значення, щоб результат був передбачуваним (а в деяких випадках важливий порядок: завантаження виконуваного коду є одним із прикладів). Тому потрібно мати тип даних, який представляє місце в пам'яті. Навіть якщо ваше програмне середовище ховає це під абстракцією, воно все одно є.
char*
є крихким прикладом покажчиків. Вам, мабуть, краще використовувати std::string
(або якийсь кращий тип, який обробляє вашу унікальність / ансі / багатобайтову особливість), ніж char*
. Майже для будь-якого іншого прикладу покажчиків ( Employee*
, PurchaseOrder*
, ...), однак, є багато переваг:
Насправді вказівники настільки важливі, що більшість мов, схоже, не мають їх, насправді мають лише вони. Довідкові типи в C # і Java по суті є вказівниками, замаскованими як тверді об'єкти.
Тепер маніпуляція вказівником ( p++
на вказівнику чи p += delta
) - ціла історія. Деякі люди думають, що це небезпечно, деякі вважають, що це здорово. Але це ще далі від вашого питання.
Покажчики можуть бути швидшими і можуть мати менші накладні витрати, як у структурі даних, так і при зменшенні сліду виконання програми. (Будь ласка, зверніть увагу на слово "можна".)
Загалом, правило полягає в тому, що якщо ви виділили ресурс, або виконуючи власний розподіл, або змусивши щось зробити це від вашого імені, ваша робота - звільнити його, коли буде зроблено.
Тягар виконання вищезазначеного полягає в тому, щоб повернути відповідальність розробнику, а не вимагати виконання часу. Це має ще деякі переваги в тому, що речі можна довше жити, або перетинати кордони, або утилізувати у більш підходящий час, або не потрібно переносити вагу сміттєзбірника навколо.
У екзотичних випадках, що зазвичай включають винятки та сферу застосування, є деякі крайні випадки, які вимагають бути трохи обережнішими, якщо код уникає очищення. Реально ці випадки можна розробити навколо. Ми прожили без керованого коду багато десятиліть.
Часто те, що робить покажчики «важкими» - це просто не розуміння того, що відбувається на апаратному рівні. Це не що інше, як непряме.
Покажчики дають вам набагато більше необробленого доступу, і це може бути дуже корисною, розумною чи необхідною. Ви можете вказувати куди завгодно і ставитися до цього майже як до всього. Якщо ви використовуєте свої богоподібні сили для добра, це дуже, дуже добре.
Зворотна сторона, як правило, марнує, забувши випустити щось, або випустити його не раз, або посилатися на щось після його звільнення, або перешкоджаючи чомусь, коли ви нікуди не вказуєте. Ці речі часто призводять до вражаючих збоїв, і якщо чесно сказати, зазвичай це свідчить про те, що у вас є логічна проблема, а не покажчики крихкі.
Якщо ви надійний розробник, використання покажчиків не має бути більш проблематичним, ніж будь-яка інша структура даних. Знову ж таки, це не ракетна наука, і люди робили це десятиліттями, навіть не моргнувши оком. Цього дня просто навчають менше.
Все, що було сказано, якщо у вас немає необхідності в покажчиках, випадковість та екзотичні випадки, які забезпечує хороший збір сміття, робить роботу в керованих умовах набагато приємнішою. Чудово вміти схопити якусь пам’ять, використовувати її та відмовитися від неї, знаючи, що через деякий час вона може бути відкинута, якщо це має сенс зробити. Це трохи менше коду з боку кодера, в обмін на час виконання, який робить додатковий підйом.
Найкраща відповідь насправді включена у запитання: покажчики призначені для програмування низького рівня. Звичайно, якщо ви використовуєте C, не використовуйте покажчики - це як програмування однією рукою, зав'язаною за спиною, але відповідь на це - використовувати мову вищого рівня.