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

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

Итак, динамическое управление памятью – сбрасываем оковы прибитых при компиляции размеров структур!

Итак. третий тип, самый интересный в этой теме для нас – динамический тип памяти.

Как мы работали с массивами раньше? int a[BIG_SISE] Как мы работаем сейчас? Выделяем столько, сколько нужно:

#include <stdio.h>
#include <stdlib.h>

int main() {
  size_t size;

  // Создаём указатель на int
  // – по сути, пустой массив.
  int *list;

  scanf("%lu", &size);

  // Выделяем память для size элементов размером int
  // и наш "пустой массив" теперь ссылается на эту память.
  list = (int *)malloc(size * sizeof(int));

  for (int i = 0; i < size; ++i) {
    scanf("%d", list + i);
  }

  for (int i = 0; i < size; ++i) {
    printf("%d", *(list + i));
  }

  // Не забываем за собой прибраться!
  free(list);
} //*

Помимо функции malloc есть и другие. Прочитать про них можно с помощью man malloc. Все они выделяют память, но различаются механизмы работы ОС с памятью. Например, можно повторно перевыделять память, а не запрашивать новую у ОС.

void * malloc(size_t size);

Но в общем и целом это функция, выделяет size байт неинициализированной памяти (не нули, а мусор).

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

Если неуспешно – NULL. Также errno будет равен ENOMEM (эту замечательную переменную мы рассмотрим позднее). То есть правильнее было написать:

#include <stdio.h>
#include <stdlib.h>

int main() {
  size_t size;
  int *list;

  scanf("%lu", &size);
  list = (int *)malloc(size * sizeof(int));

  if (list == NULL) {
    goto error;
  }

  for (int i = 0; i < size; ++i) {
    scanf("%d", list + i);
  }

  for (int i = 0; i < size; ++i) {
    printf("%d", *(list + i));
  }

  free(list);
  return 0;

error:
  return 1;
} //*

Очищать NULL указатель не нужно

#include <stdlib.h>

int main() {
  free(NULL);
}

– в том же clang всё пройдёт нормально (сделает ничто), но в более экзотических случаях вполне может крэшнуть программу.

Рядом с malloc и free в мане можно увидеть ещё:

  • void * calloc (size_t count, size_t size);

    Равно как и malloc выделит память под count объектов размером по size байт. Выделяемая память инициализируется нулями.

  • void * realloc (void *ptr, size_t size);

    Перевыделяет (если может) память, на которую указывает ptr, в размере size байт. Если не хватает места для увеличения выделенной памяти, на которое указывает ptr, realloc создает новое выделение (аллокацию), копирует старые данные, на которые указывает ptr, освобождает старое выделение и возвращает указатель на выделенную память.

    Если ptr равен NULL, realloc идентичен вызову malloc.

    Если size равен нулю, а ptr не NULL, выделяется кусок памяти минимального размера, а исходная освобождается.

  • void * reallocf (void *ptr, size_t size);

    Придумка из FreeBSD API. Как и realloc, но если не сможет перевыделить, очищает принятый указатель.

  • void * valloc (size_t size);

    Как и malloc, но выделенная память выравнивается по границе страницы.

Изображение Изучаем язык программирования Си