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