Итак. третий тип, самый интересный в этой теме для нас – динамический тип памяти.
Как мы работали с массивами раньше? 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, но выделенная память выравнивается по границе страницы.