Указатели для начинающих (Pointers) - Динамическое распределение

ОГЛАВЛЕНИЕ

Динамическое распределение

Динамическое распределение наверняка является ключевой темой по отношению к указателям. Оно используется для того, чтобы распределить память без необходимости в определении переменных и затем заставить указатели указывать на них. Хотя данный принцип может показаться запутывающим, на самом деле он прост. Следующий код распределяет память под тип integer:

int *pNumber;
pNumber = new int;

Первая строка объявляет указатель pNumber. Вторая строка распределяет память для типа integer и затем заставляет pNumber указывать на новую память. Вот еще один пример с использованием типа double:

double *pDouble;
pDouble = new double;

Формула одинакова во всех случаях, поэтому тут ошибиться сложно. Динамическое распределение отличается тем, что память не удаляется при возврате функции или когда выполнение выходит за рамки текущего блока. Если мы перепишем указанный выше пример с использованием динамического распределения, то теперь все будет работать как нужно:

#include <stdio.h>

int *pPointer;

void SomeFunction()
{
    // заставляем pPointer указывать на новое значение типа integer
    pPointer = new int;
    *pPointer = 25;
}

void main()
{
    SomeFunction(); // заставляем pPointer указывать на что-нибудь
    printf("Значение *pPointer: %d\n", *pPointer);
}

Изучите и скомпилируйте указанный выше код. Убедитесь в том, что вы понимаете, как он работает. Когда вызывается SomeFunction, она распределяет некоторую память и заставляет pPointer указывать на нее. На этот раз, когда функция возвращается, память остается действительной, поэтому pPointer все еще указывает на что-то пригодное. И это все, что касается динамического распределения! Вам стоит понять и разобраться в этом, и только тогда продолжать читать данную статью, где мы расскажем про другую ошибку в данном коде.

Распределение и удаление памяти

Есть некоторые вещи, которые имеют серьезные последствия, хотя их же можно с легкостью исправить. Проблема заключается в том, что хотя память, которую вы динамически распределили, сохраняет свои значения, она на самом деле не будет автоматически удалена. То есть память будет занята до того, как вы скажете компьютеру о том, что вам она больше не нужна. Проблемы появляются в том случае, если вы не оповещаете компьютер о том, что она вам не нужна, и место, которое могло быть использовано другими программами или частями вашего приложения, будет занято. Со временем это приведет к системным сбоям, когда вся память будет исчерпана, поэтому все это очень важно. Освобождение памяти не сложная процедура:

delete pPointer;

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

#include <stdio.h>

int *pPointer;

void SomeFunction()
{
//заставляем pPointer указывать на новое значение типа integer
pPointer = new int;
    *pPointer = 25;
}

void main()
{
    SomeFunction();// заставляем pPointer указывать на что-нибудь
            printf("Значение  of *pPointer: %d\n", *pPointer);

    delete pPointer;
}

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