Урок 9: «Динамическая память»


Постепенно мы подбираемся с вами к более сложному. Этот урок будет логическим продолжением темы указателей в C++. В этом уроке мы научимся выделять нужное количество памяти под нужды переменной.

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

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

А вот тут мы затронули важный момент – память компьютера.  Если вы знаете устройство компьютера, то наверняка скажете, что речь идет об оперативной памяти. Вы будете правы и неправы одновременно. Несмотря на то, что согласно архитектуре фон Неймана, все операции процессор должен выполнять в памяти, структура любой компилируемой программы такова, что состоит из стека и остальной памяти, называемой кучей.

Стек – это специальная структура данных, предназначенная для быстрого доступа к данным.  Эту структуру  еще часто называют LIFO (Last In First Out)– последним пришел, первым ушел. Подробнее о стеке и других динамических структурах поговорим в других уроках.  Вам пока важно знать, что это такое. Стек представляет собой, как бы обойму, в которую вместо патрона загоняется очередная переменная. Не хочется вдаваться в технические подробности в этом уроке. Просто скажу что в силу своей природы стековая память работает гораздо быстрее, чем обычная.  Почему так происходит, расскажу в уроке, посвященном динамическим структурам памяти.

Стек многим хорош, но вот у него есть маленькая проблема – ограниченный объем памяти. Примитивные типы данных занимают мало памяти и поэтому помещение их в стек является логически правильным решением, ускоряющим работу программы. Однако в C++, равно как и в других компилируемых языках, существуют громоздкие типы данных типа массивов, структур и классов. Переменные этих типов могут занимать обширные области памяти, что может привести к переполнению стека и экстренному прекращению работы вашей программы.  Это очень неприятный момент в кодировании. Чтобы избежать подобной участи, была придумана концепция размещения таких громоздких типов данных в свободной области памяти, именуемой кучей. Фактически, куча – это вся ваша оперативная память. Гигабайт или 4 Гигабайта – роли не играет. Все это будет кучей.

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

Несмотря на то, что стеку  я посвящу отдельный урок, поясню как он работает. Я уже говорил, что это своеобразная обойма, в которую помещаются одна за другой переменные, как бы вталкиваемые в эту обойму (недаром эту операцию называют push). Вы уже применяли функции и наверняка использовали в них переменные. Вы не задумывались над тем, куда они девались после вызова функции? Правильно, они стирались. И происходило это благодаря механизму стека, в который помещались эти переменные. Как только они стали не нужны и программа осуществила выход из функции, указатель в стеке просто сдвинулся в низ, как бы отсекая область с переменными той функции. Графически я попытался изобразить это так:

В итоге часть стека просто стирается. Однако в куче все несколько иначе. Да, в стеке мы сотрем указатель на переменную, но сама переменная будет «жить» в куче. Такая переменная уже становится мусором. C++ не умеет собирать мусор, кладя этот сизифов труд на плечи программистов. Тем не менее, уже в середине этого курса мы с вами напишем сборщик мусора для C++.

Для того, чтобы разместить переменную в куче, для нее нужно динамически выделить память. В C это делалось при помощи функций malloc и calloc. Давайте посмотрим, как это можно сделать:

int* dim=(int*)malloc (sizeof (int));
*dim=34;
cout<<*dim<<endl;
free (dim);

Как видите, мы вначале объявили динамическую переменную dim и выделили для нее память посредством malloc. Обратите внимание, что malloc и calloc возвращают тип void* (о нем мы поговорим в следующем уроке), поэтому мы приводим переменную к типу int*. Функция имеет единственный параметр – размер выделяемой памяти. Чтобы не ошибиться, я указал размер памяти через sizeof. Затем я присвоил динамической переменной значение 34. Теперь обратите внимание – динамическая переменная должна быть обязательно освобождена! Это делается при помощи функции free, параметром которой является наша переменная.

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

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

int* dim=new int;
*dim=34;
cout<<*dim<<endl;
delete dim;
dim=NULL; // явным образом очистим указатель от мусора.

Как видите, принцип практически тот же самый. Мы объявили динамическую переменную, выделили память для нее (причем компилятор сделал это сам за нас), и потом освободили память посредством delete. Затем я явным образом присвоил указателю dim значение NULL – пустой ссылки (в Паскале это nil). Это нужно для того, чтобы указатель не хранил адрес мусора.

Кстати, теперь  переменную dim можно использовать как простой указатель.  В общем, потренируйтесь.

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

<<Предыдущий урок                                                          Следующий урок>>

Обращение к читателям

Рубрика: Уроки по С++

Комментарии

20 коммент. на “Урок 9: «Динамическая память»”
  1. Дмитрий:

    Ай ай ай, а где же следующие статейки?

    • Вячеслав "VeGA" Головлев:

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

      • Дмитрий:

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

  2. tolanych:

    Жду не дождусь продолжения уроков. Огромное спасибо за этот курс, понятный до безобразия:)

  3. Данил:

    Спасибо вам за уроки,очень жду практических заданий/уроков с написанием игр

  4. Александр:

    продолжи пожалуйста уроки по С++. У тебя шикарно получается!!!

  5. admin:

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

  6. Александр:

    Все будут очень признательны тебе!!!

  7. Olga:

    Я тоже жду :)

  8. DM:

    я видимо нуб и дерево, но я так и не понял в последнем примере, что именно удаляет delete?
    он занимается объектом в куче или всё таки указателем на стеке?
    и еще — видимо совсем нубский вопрос: я знаю, что в стек кладут подряд, вынимают тоже подряд сверху. вопрос — кто это делает? и если переменные на стеке — как к ним функция получает произвольный доступ?
    или стек он только при вызове функции — «стек», а потом когда обслуживающие (ОСью) операции закончились и начинается исполнение пользовательского кода, он превращается в обычную память, к которой можно рандомно обращаться?

    (и это спрашивает человек, 20 лет назад «учивший» С в вузе)

  9. Риад:

    Спустя год… новых тем нет.

    • admin:

      И, скорее всего, не будет. У меня работа отнимает все силы и время. Уроки писать просто нет желания. Альтруизмом сыт не будешь, рекламу мало кто кликает. Фактически, блог доживает свое время…

  10. Redmoon:

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

    • admin:

      Спасибо за похвалу. Да, увы, блог загибается. Мне просто уже неохота его поддерживать. Нет времени, да и желания.
      Хабр? Что ж, мудрое решение, там пишет куча авторов. Я же один ничего не вытяну

      • Redmoon:

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

        • admin:

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

  11. DM:

    слушайте, у вас на этой странице какая-то подозрительная активность
    адблок за некоторое время зарубил уже 23К элементов…

    • admin:

      Сколько?! У меня скрипт стоит только на рекламе и он блокируется только один раз. Проверьте компьютер на вирусы

  12. DM:

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

Добавить комментарий

Внимание! Не будут добавляться комментарии в виде откровенного спама или прямого анкора на свои сайты. Все спамеры будут передаваться в базу Akismet

Подтвердите, что Вы не бот — выберите человечка с поднятой рукой: