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

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

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

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

Код компиляции

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

указатели

Давайте вернемся к началу. Каждый компьютер использует двоичный

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

, Это известно как Машинный код.

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

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

указатели

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

  • Бейсик
  • C ++
  • шепелявость

Эти языки очень старые, и многие из них были разработаны в начале 1950-х годов! Почти каждый современный язык программирования является языком высокого уровня, включая PHP и Python. Каждый день изобретается все больше языков (хотя сейчас их, вероятно, достаточно), но как именно ваш код по-прежнему работает должным образом, если компьютеры требуют машинного кода?

Здесь начинается компиляция. Компилятор — это программа, которая преобразует ваш высокоуровневый код в форму, которую можно выполнить. Это может быть другой язык высокого уровня, но обычно это ассемблер. Некоторые языки (например, Python или Java) преобразуют ваш код в промежуточный этап, называемый байткодом. Это потребует повторной компиляции позднее, что обычно выполняется по требованию, например, при запуске программы. Это известно как как раз вовремя сборник, и он довольно популярен.

Управление памятью

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

Для этого раздела будет полезно, если у вас есть понимание того, как работает RAM

,

У большинства языков есть переменные — контейнеры, в которых хранятся некоторые данные. Вы должны явно определить тип данных. Некоторые динамически типизированные языки, такие как Python или PHP, обрабатывают это для вас, но они все еще должны это делать.

Скажем, у вас есть переменная:

int myNumber;

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

«Найдите пустую память и зарезервируйте место, достаточно большое для хранения целого числа»

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

Теперь присвойте значение вашей переменной:

myNumber = 10;

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

Теперь, это все хорошо, но как места памяти становятся незарезервированными? Если бы программы зарезервировали всю память, которая им нравится, ОЗУ немедленно заполнилось бы — это сделало бы очень медленную систему.

указатели

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

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

function maths() {
int firstNumber = 1;
}
int secondNumber = 2;
print(firstNumber + secondNumber); // will not work

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

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

Введите: указатели.

указатели

На первый взгляд, указатели звучат просто. Они ссылаются (указывают) на место в памяти. Это может не отличаться от «обычных» переменных в стеке, но, поверьте мне, есть огромная разница. Указатели хранятся на куча. Это противоположность стека — он менее организован, но намного быстрее.

Давайте посмотрим, как переменные назначаются в стеке:

int numberOne = 1;
int numberTwo = numberOne;

Это простой синтаксис; Переменная номер два содержит номер один. Это значение копируется во время назначения из номер один переменная.

Если вы хотите получить адрес памяти переменной, вместо ее значения, вы должны использовать знак амперсанда (). Это называется адрес оператор, и является неотъемлемой частью вашего инструментария указателя.

int numberOne = 1;
int numberTwo = &numberOne;

Теперь номер два переменная указывает на ячейку памяти, а не копирует номер один в свою новую, новую ячейку памяти. Если бы вы вывели эту переменную, она не была бы номером один (даже если она хранится в ячейке памяти). Будет выведено место в памяти (вероятно, что-то вроде 2167, хотя оно зависит от системы и доступной оперативной памяти). Чтобы получить доступ к значению, хранящемуся в указателе, вместо места в памяти, вы должны разыменовать указатель Это напрямую обращается к значению, которое в данном случае будет номером один. Вот как вы разыменовываете указатель:

int numberTwo = *numberOne;

оператор разыменования это звездочка (*).

Это может быть трудной для понимания концепции, поэтому давайте рассмотрим ее еще раз:

  • адрес Оператор () хранит адрес памяти.
  • оператор разыменования (*) получает доступ к значению.

Синтаксис немного меняется при объявлении указателей:

int * myPointer;

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

Теперь, когда вы знаете, что такое указатели, вы можете делать с ними действительно изящные трюки! Когда используется память, ваша операционная система запускается последовательно. Вы можете думать об оперативной памяти как о голубиных дырах. Много отверстий для хранения чего-либо, только одно можно использовать одновременно. Разница здесь в том, что эти отверстия для голубей пронумерованы. При выделении памяти ваша операционная система запускается с наименьшего числа и работает. Он никогда не будет прыгать между случайными числами.

указатели

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

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

указатели

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

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

указатели

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

Вот и все на сегодня. Я надеюсь, что вы узнали что-то полезное о сложной теме. Конечно, мы не охватили все, что нужно знать — это очень сложная тема. Если вы заинтересованы в получении дополнительной информации, я настоятельно рекомендую C ++ в течение 24 часов.

Если это было немного сложно, взгляните на наше руководство по самым простым языкам программирования

,

Вы узнали, как работают указатели сегодня? Есть ли у вас какие-либо советы и приемы, которыми вы хотите поделиться с другими программистами? Перейти в комментарии и поделиться своими мыслями ниже!

Ссылка на основную публикацию
Adblock
detector