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