0Pricing
C Academy · Урок

Утечки памяти

Находите утечки и избегайте их

«Утечки памяти» — бесплатный урок C Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения C Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс C Academy содержит 4 уроков всего.

Что такое утечка памяти

Утечка памяти возникает, когда Вы выделяете память в куче, но никогда не освобождаете её и теряете единственный указатель на неё.

Память остаётся зарезервированной до завершения программы, расходуя ресурсы.

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

int main(void) {
    int *p = malloc(sizeof(int));
    *p = 5;
    printf("%d\n", *p);
    free(p);
    return 0;
}

Потеря указателя

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

Первый блок становится недоступным.

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

int main(void) {
    int *p = malloc(sizeof(int));
    free(p);
    p = malloc(sizeof(int));
    *p = 10;
    printf("%d\n", *p);
    free(p);
    return 0;
}

Утечки в циклах

Выделение памяти внутри цикла без освобождения на каждой итерации быстро увеличивает утечку.

Исправление состоит в том, чтобы освобождать память до того, как следующая итерация перезапишет указатель.

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

int main(void) {
    for (int i = 0; i < 3; i++) {
        int *p = malloc(sizeof(int));
        *p = i;
        printf("%d ", *p);
        free(p);
    }
    printf("\n");
    return 0;
}

Ранний возврат приводит к утечке

Ранний return после выделения памяти может пропустить очистку. Всегда освобождайте память на каждом пути выхода.

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

int process(int bad) {
    int *p = malloc(sizeof(int));
    if (bad) {
        free(p);
        return -1;
    }
    *p = 42;
    int r = *p;
    free(p);
    return r;
}

int main(void) {
    printf("%d\n", process(0));
    return 0;
}

Шаблон очистки с goto

Единая метка очистки, к которой ведёт goto, гарантирует наличие одного места для освобождения всей памяти и позволяет избежать дублирования вызовов free.

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

int main(void) {
    int rc = 1;
    int *p = malloc(sizeof(int));
    if (!p) goto done;
    *p = 7;
    printf("%d\n", *p);
    rc = 0;
done:
    free(p);
    return rc;
}

Сопоставляйте каждое выделение памяти с освобождением

Простейшее правило: для каждого вызова malloc, calloc или realloc должен быть ровно один соответствующий вызов free.

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

int main(void) {
    char *a = malloc(8);
    char *b = calloc(4, sizeof(char));
    a[0] = 'x';
    printf("%c %d\n", a[0], b[0]);
    free(a);
    free(b);
    return 0;
}

Освобождение вложенных выделений

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

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

typedef struct {
    int *data;
} Box;

int main(void) {
    Box *b = malloc(sizeof(Box));
    b->data = malloc(3 * sizeof(int));
    b->data[0] = 1;
    printf("%d\n", b->data[0]);
    free(b->data);
    free(b);
    return 0;
}

Освобождение массива указателей

Если Вы выделили массив указателей и каждый элемент указывает на отдельно выделенную область памяти, сначала освободите все элементы, а затем сам массив.

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

int main(void) {
    int n = 3;
    int **rows = malloc(n * sizeof(int *));
    for (int i = 0; i < n; i++) {
        rows[i] = malloc(2 * sizeof(int));
        rows[i][0] = i;
    }
    for (int i = 0; i < n; i++) free(rows[i]);
    free(rows);
    printf("freed all rows\n");
    return 0;
}

Дисциплина владения

Определите, кто владеет каждым выделенным блоком и отвечает за его освобождение. Задокументируйте это, чтобы вызывающий код знал, должен ли он освобождать возвращённый указатель.

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

char *make_greeting(void) {
    char *s = malloc(6);
    s[0]='h'; s[1]='i'; s[2]='\0';
    return s;
}

int main(void) {
    char *g = make_greeting();
    printf("%s\n", g);
    free(g);
    return 0;
}

Инструменты для поиска утечек

Такие инструменты, как Valgrind и AddressSanitizer, находят утечки, отслеживая каждое выделение памяти и показывая, какие блоки так и не были освобождены.

Они необходимы для проверки настоящих программ.

Правильный жизненный цикл выделения памяти

Общий порядок таков: выделить память, проверить результат, использовать её, освободить на каждом пути и обнулить указатель. Это позволяет избежать утечек в программе.

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

int main(void) {
    int *p = malloc(4 * sizeof(int));
    if (!p) return 1;
    for (int i = 0; i < 4; i++) p[i] = i + 1;
    int sum = 0;
    for (int i = 0; i < 4; i++) sum += p[i];
    printf("sum = %d\n", sum);
    free(p);
    p = NULL;
    return 0;
}

Быстрая проверка

Проверьте, насколько хорошо Вы понимаете утечки памяти.

Повторение

Вы научились предотвращать утечки памяти:

  • Сопоставляйте каждому выделению памяти ровно один вызов free.
  • Освобождайте память на каждом пути выхода, включая ранние возвраты и ошибки.
  • Освобождайте вложенные выделения и выделения для массивов указателей изнутри наружу.
  • Чётко определяйте владение и используйте такие инструменты, как Valgrind, для проверки.

Часто задаваемые вопросы

Урок «Утечки памяти» бесплатный?

Да — полный текст урока «Утечки памяти» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс C Academy, подпишись на CoddyKit PRO. Курс C Academy содержит 4 уроков всего.

Чему я научусь в уроке «Утечки памяти»?

Находите утечки и избегайте их Ты практикуешь C Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать C Academy?

Предыдущий опыт не требуется. C Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.

Сколько времени занимает урок «Утечки памяти»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке C Academy?

Да. Каждый урок C Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. malloc и free
  2. calloc и realloc
  3. Утечки памяти
  4. Висячие указатели
← Назад к C Academy