freeCodeCamp/guide/russian/c/dynamic-memory-management/index.md

8.5 KiB
Raw Blame History

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

Управление динамической памятью

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

Пример

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

#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 (это указатель на область неизвестного типа данных) в новое пространство памяти, которое мы только что выделили. Давайте посмотрим, как использовать эту функцию шаг за шагом:

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

sizeof(int) 

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

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

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

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

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

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

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

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

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

  free(arrayPointer); 

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

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

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

  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 . Если вы не будете следовать этому шаблону, обычно будет передан отказ от сегментации, и программа выйдет из строя. Эти ошибки могут быть временными и сложными для отладки - например, освобожденная память обычно не сразу восстанавливается системой, а оборванные указатели могут сохраняться некоторое время и, похоже, работают.