---
title: Dinamic Memory Management
localeTitle: Управление динамической памятью
---
# Управление динамической памятью

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

## Пример

Вот простой пример, в котором мы выделяем массив, запрашивающий у пользователя выбор измерения

```C
#include <stdio.h> 
 #include <stdlib.h> 
 
 int main(void) { 
    int arrayDimension,i; 
    int* arrayPointer; 
 
    scanf("Please insert the array dimension:%d",arrayDimension); 
    arrayPointer = (int*)malloc(sizeof(int)*arrayDimension); 
 
    if(arrayPointer == NULL){ 
      printf("Error allocating memory!"); 
      return -1; 
     } 
 
     for(i=0;i<arrayDimension;i++){ 
        printf("Insert the %d value of the array:",i+1); 
        scanf("%d\n",arrayPointer[i]); 
     } 
 
    free(arrayPointer); 
    return 0; 
 } 
```

Как вы можете видеть, чтобы выделить пространство в динамической памяти, вам нужно знать, как работают указатели на C. Магическая функция здесь - это `malloc` который будет возвращать как вывод указателя void (это указатель на область неизвестного типа данных) в новое пространство памяти, которое мы только что выделили. Давайте посмотрим, как использовать эту функцию шаг за шагом:

## Выделение массива во время выполнения

```C
sizeof(int) 
```

Начнем с `sizeof` . `malloc` должен знать, сколько места выделяется для ваших данных. Фактически переменная `int` будет использовать меньше места для хранения, а затем `double` . Обычно небезопасно принимать размер любого типа данных. Например, хотя большинство реализаций C и C ++ в 32-битных системах определяют тип int как четыре октета, этот размер может измениться, когда код портируется в другую систему, нарушая код. `sizeof` мере того, как его имя предполагает, генерирует размер переменной или типа данных.

```C
arrayPointer = (int*) malloc(sizeof(int) * arrayDimension); 
```

В этом примере malloc выделяет память и возвращает указатель на блок памяти. Размер выделенного блока равен количеству байтов для одного объекта типа int, умноженного на `arrayDimension` , при условии, что система имеет достаточно свободного места. Но что, если у вас недостаточно места или `malloc` не может выделить его по другим причинам?

## Проверка вывода malloc

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

```C
    if(arrayPointer == NULL) 
      printf("Error allocating memory!"); 
```

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

## Слово на бесплатном ()

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

```C
  free(arrayPointer); 
```

В конце вы точно поймете, что проверка значения `arrayPointer` необходимо для предотвращения ошибки с использованием `free` функции. Если значение `arrayPointer` равно `NULL` вы могли бы исправить какую-то ошибку.

## Другие функции, подобные malloc

Иногда вам нужно не только резервировать новую область памяти для ваших операций, но также может потребоваться инициализировать все байты до нуля. Для этого используется `calloc` . В других случаях вы хотите изменить размер памяти, на которую указывает указатель. Например, если у вас есть указатель, действующий как массив размера `n` и вы хотите изменить его на массив размера `m` , вы можете использовать `realloc` .

```C
  int *arr = malloc(2 * sizeof(int)); 
  arr[0] = 1; 
  arr[1] = 2; 
  arr = realloc(arr, 3 * sizeof(int)); 
  arr[2] = 3; 
```

## Общие ошибки

Неправильное использование распределения динамической памяти часто может быть источником ошибок, как вы видели раньше. Наиболее распространенные ошибки:

*   Не проверять наличие сбоев Выделение памяти не гарантирует успеха, и вместо этого может возвращать нулевой указатель. Используя возвращаемое значение, не проверяя, выполнено ли выделение, вызывает неопределенное поведение. Это обычно приводит к сбою (из-за возникшей ошибки сегментации при разыменовании нулевого указателя), но нет никакой гарантии, что произойдет сбой, поэтому полагаться на это также может привести к проблемам.
*   Утечка памяти Неспособность освободить память с помощью `free` ведет к созданию памяти без повторного использования, которая больше не используется программой.
*   Логические ошибки Все распределения должны следовать той же схеме: выделение с помощью `malloc` , использование для хранения данных, используя Deallocation `free` . Если вы не будете следовать этому шаблону, обычно будет передан отказ от сегментации, и программа выйдет из строя. Эти ошибки могут быть временными и сложными для отладки - например, освобожденная память обычно не сразу восстанавливается системой, а оборванные указатели могут сохраняться некоторое время и, похоже, работают.