Первая функция printf
пытается вывести строку, полученную от указателя null
; далее sprintf
пытается записать по указателю null
. В данном случае Linux (под видом библиотеки GNU С) простила чтение и просто предоставила "магическую" строку, содержащую символы (null)\0
. Система не столь терпима в случае записи и просто завершила программу. Такое поведение порой полезно при выявлении программных ошибок.
Если вы повторите попытку, но не будете использовать библиотеку GNU С, вы обнаружите, что безадресное чтение не разрешено. Далее приведена программа memory5b.c:
#include
#include
#include
int main {
char z = *(const char *)0;
printf("I read from location zero\n");
exit(EXIT_SUCCESS);
}
Вы получите следующий результат:
$ ./memory5b
Segmentation fault
В этот раз вы пытаетесь прочесть непосредственно из нулевого адреса. Между вами и ядром теперь нет GNU-библиотеки libc, и программа прекращает выполнение. Имейте в виду, что некоторые системы UNIX разрешают читать из нулевого адреса, ОС Linux этого не допускает.
Освобождение памяти
До сих пор мы выделяли память и затем надеялись на то, что по завершении программы использованная нами память не будет потеряна, К счастью, система управления памятью в ОС Linux вполне способна с высокой степенью надежности гарантировать возврат памяти в систему по завершении программы. Но большинство программ просто не хотят распределять память, используют ее очень короткий промежуток времени и затем завершаются. Гораздо более распространено динамическое использование памяти по мере необходимости.
Программы, применяющие память на динамической основе, должны всегда возвращать неиспользованную память диспетчеру распределения памяти malloc
с помощью вызова free
. Это позволяет выделить блоки, нуждающиеся в повторном объединении, и дает возможность библиотеке malloc
следить за памятью, вместо того, чтобы заставлять приложение управлять ею. Если выполняющаяся программа (процесс) использует, а затем освобождает память, эта освободившаяся память остается выделенной процессу. За кадром система Linux управляет блоками памяти, которые программист использует как набор физических "страниц" в памяти, размером 4 Кбайт каждая. Но если страница памяти в данный момент не используется, диспетчер управления памятью ОС Linux сможет переместить ее из оперативной памяти в область свопинга (это называется обменом страниц), где она слабо влияет на потребление ресурсов. Если программа пытается обратиться к данным на странице, которая была перенесена в область свопинга, Linux на очень короткое время приостанавливает программу, возвращает страницу обратно из области свопинга в физическую память и затем разрешает программе продолжить выполнение так, будто данные все время находились в оперативной памяти.
#include
void free(void *ptr_to_memory);
Вызов free
следует выполнять только с указателем на память, выделенную с помощью вызова malloc
, calloc
или realloc
. Очень скоро вы встретитесь с функциями calloc
и realloc
. А сейчас выполните упражнение 7.6.
Эта программа называется memory6.c.
#include
#include
#define ONE_K (1024)
int main {
char *some_memory;
int exit code = EXIT_FAILURE;
some_memory = (char*)malloc(ONE_K);
if (some_memory != NULL) {
free(some_memory);
printf("Memory allocated and freed again\n");
exit_code = EXIT_SUCCESS;
}
exit(exit_code);
}
Вывод программы следующий:
$ ./memory6
Memory allocated and freed again
Как это работает
Эта программа просто показывает, как вызвать функцию free
с указателем, направленным на предварительно выделенную область памяти.
Помните о том, что после вызова free
для освобождения блока памяти этот блок больше не принадлежит процессу. Он больше не управляется библиотекой malloc
. Никогда не пытайтесь читать из области памяти или писать в область памяти, для которой была вызвана функция free
.
Другие функции распределения памяти
Две другие функции распределения или выделения памяти calloc
и realloc
применяются не так часто, как malloc
и free
.
Далее приведены их прототипы:
#include