Управление памятью в C

Здравствуйте, будущие маги кодирования! Сегодня мы погружаемся в fascинирующий мир управления памятью в C. Не волнуйтесь, если вы новички в программировании; я буду вести вас через это путешествие шаг за шагом, как я делал это для countless студентов на протяжении многих лет моей преподавательской деятельности. Так что надевайте свои виртуальные каски и давайте исследуем строительную площадку компьютерной памяти!

C - Memory Management

Функции для динамического управления памятью в C

Before мы начнем строить наши memory небоскребы, давайте familiarize ourselves с инструментами, которые мы будем использовать. В C у нас есть набор функций, которые помогают нам управлять памятью динамически. Представьте эти функции как вашу надежную toolboxes:

Функция Цель
malloc() Выделяет блок памяти
calloc() Выделяет и initializes несколько блоков памяти
realloc() Изменяет размер previously выделенного блока памяти
free() Возвращает выделенную память системе

Эти функции как бригада на нашей строительной площадке memory. У каждого есть своя special работа, и мы будем closely знакомиться с ними всеми.

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

Представьте, что вы planning вечеринку, но не уверены, сколько гостей прийдет. Вот где comes в handy динамическое выделение памяти! Вместо того чтобы устанавливать фиксированное количество стульев, вы можете добавлять или удалять их по мере необходимости. Давайте посмотрим, как мы делаем это в C.

Функция malloc()

Наш первый супергерой memory выделения - malloc(). Он означает "memory allocation" и используется для запроса блока памяти у системы.

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

int main() {
int *numbers;
int size = 5;

numbers = (int*)malloc(size * sizeof(int));

if (numbers == NULL) {
printf("Memory allocation failed!\n");
return 1;
}

for (int i = 0; i < size; i++) {
numbers[i] = i * 10;
printf("numbers[%d] = %d\n", i, numbers[i]);
}

free(numbers);
return 0;
}

Давайте разберем это:

  1. Мы включаем <stdlib.h>, потому что это где живет malloc().
  2. Мы declare pointer numbers для хранения нашего динамически выделенного массива.
  3. malloc(size * sizeof(int)) запрашивает достаточно памяти для хранения 5 целых чисел.
  4. Мы cast результат к (int*), потому что malloc() возвращает void pointer.
  5. Всегда проверяйте, succeeded ли malloc()! Если он возвращает NULL, у нас нет шансов (и памяти).
  6. Мы можем использовать numbers как обычный массив.
  7. Не забудьте free() память, когда вы закончите!

Функция calloc()

Теперь встречайте calloc(), neat freak memory выделения. В то время как malloc() дает вам память с whatever мусор был там до этого, calloc() убирает за собой, инициализируя всю выделенную память в ноль.

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

int main() {
int *numbers;
int size = 5;

numbers = (int*)calloc(size, sizeof(int));

if (numbers == NULL) {
printf("Memory allocation failed!\n");
return 1;
}

for (int i = 0; i < size; i++) {
printf("numbers[%d] = %d\n", i, numbers[i]);
}

free(numbers);
return 0;
}

Основные различия здесь:

  1. calloc() принимает два аргумента: количество элементов и размер каждого элемента.
  2. Все элементы инициализируются в ноль, так что наш вывод будет всеми нулями.

Изменение и высвобождение памяти

Иногда наша вечеринка становится больше или меньше, чем мы ожидали. Вот где comes в handy realloc()!

Функция realloc()

realloc() как魔术ник, который может расширять или уменьшать наш блок памяти.

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

int main() {
int *numbers;
int size = 5;

numbers = (int*)malloc(size * sizeof(int));

if (numbers == NULL) {
printf("Memory allocation failed!\n");
return 1;
}

for (int i = 0; i < size; i++) {
numbers[i] = i * 10;
printf("numbers[%d] = %d\n", i, numbers[i]);
}

// Давайте расширяем наш массив
size = 10;
numbers = (int*)realloc(numbers, size * sizeof(int));

if (numbers == NULL) {
printf("Memory reallocation failed!\n");
return 1;
}

// Заполним новые элементы
for (int i = 5; i < size; i++) {
numbers[i] = i * 10;
}

// Выведем все элементы
for (int i = 0; i < size; i++) {
printf("numbers[%d] = %d\n", i, numbers[i]);
}

free(numbers);
return 0;
}

Вот что происходит:

  1. Мы начинаем с 5 элементов, как и раньше.
  2. Мы используем realloc() для расширения нашего массива до 10 элементов.
  3. realloc() сохраняет нашу исходную данные и дает нам больше места.
  4. Мы заполняем новые элементы и выводим все.

Функция free()

Last но не least, у нас есть free(), бригада уборки нашей memory управления команде. Всегда помните, чтобы free() вашу динамически выделенную память, когда вы закончите с ней!

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

int main() {
int *numbers = (int*)malloc(5 * sizeof(int));

if (numbers == NULL) {
printf("Memory allocation failed!\n");
return 1;
}

for (int i = 0; i < 5; i++) {
numbers[i] = i * 10;
printf("numbers[%d] = %d\n", i, numbers[i]);
}

free(numbers);  // Уборка!
numbers = NULL; // Хорошая практика, чтобы избежать использования высвобожденной памяти

// Попытка использовать 'numbers' теперь была бы плохой идеей!

return 0;
}

Помните:

  1. Всегда free() выделяемую вами память, когда вы закончите с ней.
  2. Установите pointer к NULL после высвобождения, чтобы избежать случайного использования высвобожденной памяти.
  3. Никогда не пытайтесь free() память, которую вы не выделяли динамически.

И вот оно,folks! Мы построили наши memory управление небоскребы, научились выделять место для наших вечеринок, перераспределять место по мере необходимости и убирать afterwards. Помните, хорошее управление памятью как быть хорошим хозяином - всегда убедитесь, что у вас есть достаточно места для ваших гостей, будьте гибки с вашими arrangement и彻底 убирайте после того, как вечеринка закончилась!

Продолжайте практиковать эти концепции, и вскоре вы станете master architect памяти вашей программы. Счастливого кодирования и пусть ваши программы всегда работают без утечек!

Credits: Image by storyset