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