Выделение массива
Зарезервируйте память в куче.
«Выделение массива» — бесплатный урок C Academy на CoddyKit. Это урок 1 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения C Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс C Academy содержит 4 уроков всего.
Зачем нужны динамические массивы
Обычный массив имеет фиксированный размер, задаваемый во время компиляции. Но часто до запуска программы неизвестно, сколько элементов понадобится.
Динамические массивы решают эту проблему: во время выполнения Вы запрашиваете у операционной системы блок памяти с помощью malloc, а размер задаёте переменной.
Знакомство с malloc
malloc (выделение памяти) находится в <stdlib.h>. Ему передаётся количество байтов, а он возвращает указатель на этот блок или NULL, если операция не удалась.
Память выделяется в куче и остаётся занятой, пока Вы не освободите её.
int *p = malloc(10 * sizeof(int));Определение размера с помощью sizeof
Никогда не задавайте количество байтов вручную. Используйте sizeof, чтобы код корректно работал на разных платформах.
Чтобы выделить место для n целых чисел, умножьте n на sizeof(int). Распространённая идиома — n * sizeof(*p), использующая собственный тип указателя.
int *p = malloc(n * sizeof(*p));Всегда проверяйте NULL
Если системе не хватает памяти, malloc возвращает NULL. Разыменование нулевого указателя приводит к аварийному завершению программы.
Проверяйте результат до его использования. Эта простая привычка предотвращает множество трудно обнаруживаемых сбоев.
int *p = malloc(n * sizeof(*p));
if (p == NULL) {
fprintf(stderr, "out of memory\n");
return 1;
}Полное выделение памяти
Вот полноценная программа, которая выделяет место для 5 целых чисел, заполняет его и выводит их.
Обратите внимание на симметрию: malloc в начале и free в конце.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int n = 5;
int *a = malloc(n * sizeof(*a));
if (!a) return 1;
for (int i = 0; i < n; i++) a[i] = i * i;
for (int i = 0; i < n; i++) printf("%d\n", a[i]);
free(a);
return 0;
}malloc не обнуляет память
Память, полученная через malloc, не инициализирована: в ней находятся произвольные остаточные данные.
Чтение до записи приводит к непредсказуемым значениям. Всегда присваивайте значение каждому элементу до его чтения.
int *a = malloc(3 * sizeof(*a));
/* a[0], a[1], a[2] hold garbage here */
a[0] = 10;calloc обнуляет память за Вас
calloc(count, size) выделяет место для count элементов размером size байт и устанавливает каждый байт в ноль.
Используйте его, когда нужен чистый массив, заполненный нулями. Кроме того, он защищает от переполнения при умножении.
int *a = calloc(5, sizeof(*a));
/* every element is now 0 */calloc в действии
Эта программа использует calloc и подтверждает, что массив изначально заполнен нулями, прежде чем изменить его.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int n = 4;
int *a = calloc(n, sizeof(*a));
if (!a) return 1;
for (int i = 0; i < n; i++) printf("%d\n", a[i]);
free(a);
return 0;
}Индексация блока
Указатель на блок в куче ведёт себя так же, как имя массива. С помощью a[i] можно читать и записывать любой элемент с индексом от 0 до n-1.
Внутри a[i] эквивалентно *(a + i).
int *a = malloc(3 * sizeof(*a));
a[0] = 1;
*(a + 1) = 2; /* same as a[1] = 2 */
a[2] = 3;Следите за границами
Если Вы выделили n элементов, допустимые индексы — от 0 до n-1. Запись в a[n] является неопределённым поведением.
C не проверяет границы самостоятельно, поэтому ошибка на единицу может незаметно повредить память.
int *a = malloc(3 * sizeof(*a));
a[2] = 99; /* OK, last valid index */
/* a[3] = 0; BUG: out of bounds */Чтение размера во время выполнения
В этом и заключается настоящая сила: размер может поступать из ввода, файла или вычисления. Один и тот же код выделит место для 2 или 2 миллионов элементов.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int n = 6; /* could be scanf'd */
long *a = malloc(n * sizeof(*a));
if (!a) return 1;
long sum = 0;
for (int i = 0; i < n; i++) { a[i] = i + 1; sum += a[i]; }
printf("%ld\n", sum);
free(a);
return 0;
}Быстрая проверка
Проверьте, насколько хорошо Вы понимаете выделение памяти.
Повторение
Динамический массив выделяют с помощью malloc(n * sizeof(*p)) или выделяют и заполняют нулями с помощью calloc(n, sizeof(*p)).
Всегда проверяйте NULL, помните, что malloc оставляет произвольные данные, используйте индексы от 0 до n-1 и сопровождайте каждое выделение вызовом free. Далее Вы научитесь изменять размер блока, сохраняя его данные.
Часто задаваемые вопросы
Урок «Выделение массива» бесплатный?
Да — полный текст урока «Выделение массива» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс C Academy, подпишись на CoddyKit PRO. Курс C Academy содержит 4 уроков всего.
Чему я научусь в уроке «Выделение массива»?
Зарезервируйте память в куче. Ты практикуешь C Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать C Academy?
Предыдущий опыт не требуется. C Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 1 из 4.
Сколько времени занимает урок «Выделение массива»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке C Academy?
Да. Каждый урок C Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Выделение массива
- Изменение размера с realloc
- Многоразовый тип вектора
- Освобождение памяти и предотвращение утечек