Промышленное производство
Промышленный Интернет вещей | Промышленные материалы | Техническое обслуживание и ремонт оборудования | Промышленное программирование |
home  MfgRobots >> Промышленное производство >  >> Industrial programming >> Язык C

Динамическое выделение памяти в C: мастерство malloc, calloc, realloc и free

Прежде чем погружаться в динамическое выделение памяти в C, важно понять, как управляется память в языке.

Как работает управление памятью в C

Когда вы объявляете переменную примитивного типа, компилятор автоматически выделяет под нее место в стеке. Например, float обычно занимает 4 байта (зависит от платформы). Вы можете подтвердить это с помощью оператора sizeof:

#include <stdio.h> int main() { float x; printf("The size of float is %d bytes", sizeof(x)); return 0; }

Вывод будет:

The size of float is 4 bytes

Массив заданного размера также выделяется непрерывно в стеке, каждый элемент занимает размер своего типа:

#include <stdio.h> int main() { float arr[10]; printf("The size of the float array with 10 elements is %d", sizeof(arr)); return 0; }

Результат:

The size of the float array with 10 elements is 40

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

Динамическое выделение памяти в C

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

Рассмотрим каждую функцию подробно.

Функция malloc()

Функция malloc() означает «memory allocation». Она резервирует блок памяти заданного размера и возвращает указатель на него. Указатель обычно приводят к желаемому типу:

ptr = (cast_type *) malloc(byte_size);

Пример:

#include <stdlib.h> int main(){ int *ptr; ptr = malloc(15 * sizeof(*ptr)); /* 15 целых чисел */ if (ptr != NULL) { *(ptr + 5) = 480; /* шестой элемент */ printf("Value of the 6th integer is %d", *(ptr + 5)); } }

Вывод:

Value of the 6th integer is 480

Ключевые моменты:

  1. Используйте sizeof(*ptr) для устойчивости кода к изменению типов.
  2. Проверяйте возврат NULL для обнаружения неудачи выделения.
  3. Выделенная память непрерывна; обращайтесь к ней как к массиву, используя арифметику указателей.

Динамическое выделение не ограничено примитивными типами; работает со структурами, символьными массивами и др.

Функция free()

Память, выделенная через malloc(), calloc() или realloc(), должна быть явно освобождена для предотвращения утечек. Функция free() выполняет эту задачу:

#include <stdio.h> int main() { int* ptr = malloc(10 * sizeof(*ptr)); if (ptr != NULL){ *(ptr + 2) = 50; printf("Value of the 2nd integer is %d", *(ptr + 2)); } free(ptr); }

Вывод:

 Value of the 2nd integer is 50

Функция calloc()

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

ptr = (cast_type *) calloc(n, size);

Пример — суммирование арифметической последовательности:

#include <stdio.h> int main() { int i, *ptr, sum = 0; ptr = calloc(10, sizeof(int)); if (ptr == NULL) { printf("Error! memory not allocated."); exit(0); } for (i = 0; i < 10; ++i) { *(ptr + i) = i; sum += *(ptr + i); } printf("Sum = %d", sum); free(ptr); return 0; }

Результат:

Sum = 45

calloc() vs. malloc()

Ключевые различия:

Функция realloc()

Функция realloc() изменяет размер существующего выделения, сохраняя его содержимое:

ptr = realloc(ptr, newsize);

Пример — расширение строкового буфера:

#include <stdio.h> int main () { char *ptr = malloc(10); strcpy(ptr, "Programming"); ptr = realloc(ptr, 20); // увеличить strcat(ptr, " In 'C'"); printf("%s, Address = %u", ptr, ptr); free(ptr); return 0; }

Если перераспределение не удается, realloc() возвращает NULL, а исходный блок остается валидным.

Динамические массивы

Динамические массивы позволяют количеству элементов расти во время выполнения — частый паттерн в алгоритмах и структурах данных:

#include <stdio.h> int main() { int *arr_dynamic = NULL; int elements = 2, i; arr_dynamic = calloc(elements, sizeof(int)); for (i = 0; i < elements; i++) arr_dynamic[i] = i; for (i = 0; i < elements; i++) printf("arr_dynamic[%d]=%d\n", i, arr_dynamic[i]); elements = 4; arr_dynamic = realloc(arr_dynamic, elements * sizeof(int)); printf("After realloc\n"); for (i = 2; i < elements; i++) arr_dynamic[i] = i; for (i = 0; i < elements; i++) printf("arr_dynamic[%d]=%d\n", i, arr_dynamic[i]); free(arr_dynamic); }

Результат:

arr_dynamic[0]=0 arr_dynamic[1]=1 After realloc arr_dynamic[0]=0 arr_dynamic[1]=1 arr_dynamic[2]=2 arr_dynamic[3]=3

Резюме

Язык C

  1. Понимание ROM, PROM, EPROM и EEPROM: дизайн, программирование и идентификация
  2. Основы ввода-вывода в C#: Console.WriteLine, ReadLine и форматирование
  3. Освоение операторов using в C#: импорт, псевдонимы и статические директивы
  4. Управление памятью в C++: экспертное использование new и delete
  5. Четыре проверенных паттерна пользовательских функций в C
  6. Динамическое выделение памяти в C: освоение malloc, calloc, realloc и free
  7. Стандартные библиотечные функции в C: практическое руководство
  8. Динамическое выделение массивов в C++: практическое руководство с примерами кода
  9. Функции в C++: подробное объяснение с практическими примерами кода
  10. Функции в C: объявление, определение, вызов, аргументы (по значению и по ссылке), рекурсия