Разделы сайта:
Статьи по C и C++Стандартная библиотека CКнигиЮмор
Функции библиотеки stdlib.h

Работа с памятью.

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

  • Утечка памяти без освобождения. Ошибок при выполнении не вызывает, однако многие ОС не решаются удалить память, выделенную уже завершенной программой, и вконце концов вся память заканчивается, и компьютер приходится перезагружать вручную. Для ее устраниния можно использовать трассировочные макросы.
  • Использование памяти, непринадлежащей выделенной области, или просто напросто выход за границы. Очень опасная ошибка программиста, потому что средствами отладки она с трудом вылавливается. Вот яркий пример такой ошибки:
    char* szString;
    szString=malloc(15);
    fgets(szString, sizeof szString, stdin); 
    //Кто может гарантировать, что пользователь введет не больше 15 символов?
    ...
    free(szString);
  • Еще одной ошибкой является использование еще не выделенной памяти или уже освобожденной. Полагаться, что в первые микросекунды память еще не была повторно использована не стоит.

Давайте теперь размеремся, какие функции выделения и освобождения предоставляет нам стандартная библиотека С. Наибольшей популярностью пользуется функция malloc. Она выделяет память из "кучи" (специальная область памяти, которая используется для динамически-выделяемой памяти) и возвращает ее пользователю. При ошибке она возвращает указатель на ничто, то есть NULL.

void *malloc(size_t size);
Выделяет блок памяти из памяти, предоставленной программе, размером size.

Если Вы хотите использовать память под массивы, используйте функцию calloc. Она идеально подходит для выделения массивов, но следует помнить, что "близкие" указатели имеют предел по используемой памяти - 64К, для более массивных выделений следует применять "далекие" указатели (far) и функции farmalloc/farcalloc + farfree (не все среды). Так как такие блоки памяти имеются только в 16-битных средах, я не буду рассказывать о них.

void *calloc(size_t nitems, size_t size);
Выделяет память под nitems элементов, каждый из которых занимает по size байтов. При неудаче возвращает NULL.

Память, которая выделенна функциями malloc, calloc, realloc, после окончания работы с ней следует освободить, во избежание утечки. Для этого предусмотрена функция free.

void free(void *block);
Очищает block. Ничего не возвращает.

Для более быстрого доступа к памяти (например для временных объектов) применяют функцию alloca.

void *alloca(size_t size);
Выделяет память стека размером size. Память автоматически освобождается при выходе из функции.

Если Вам надо изменить размер выделенной памяти, воспользуйтесь функцией realloc.

После того, как Вы выделили память функциями realloc, malloc или calloc, ее следует очитстить функцией free.

void free(void* block);
Очищает block.

В С++ предусмотрены конструкции new и delete. По моему мнению, они более удобны, и поэтому в настоящий момент вышеперечисленные функции не так популярны. К тому же, жти два оператора просты в отладке (не необходимо самому писать трассировочную библиотеку).

Часть 2 - функции работающие с областью памяти.

Мы уже узнали, как выделять и оцищать память. Помимо определяемых пользователем инструкций по обработки памяти, стандартная библиотека С предоставляет нам несколько полезных функций. Все они располагаются в библиотеке mem.h и в целом аналогичны функциям для работы со строками string.h Общий тип указателя - void*, иногда в качестве параметров можно передать указатель на статическую память:

struct mystruct s1={0};
struct mystruct s2;
memcpy(&s2, &s1, sizeof mystruct);

Функции заполнения памяти.

В стандартной библиотеке С предусмотрено три типа заполнения памяти: копирование, перемещение и заполнение по шаблону. Первые две операции схожи, давайте рассмотрим их. Прототип memcpy (MEMory CoPY):

void *memcpy(void *dest, const void *src, size_t n);
void *_wmemcpy(void *dest, const void *src, size_t n);
Функция копирует n байтов из src в dest. Эти две области не могут перекрываться в памяти.

В первом случае области памяти не перекрываются, во втором случае они имеют общие байты, то есть перекрываются. Если в Вашей программе имеет место второй случаю, используйте функцию memmove (MEMory MOVE), однако она несколько более медленная, чем memcpy.

void *memmove(void *dest, const void *src, size_t n);
Она, как и memcpy копирует n байтов из src в dest. Эти две области могут перекрываться в памяти.

Для того, чтобы выставить дополнительное ограничение по копированию (например, до первого вхождения байта c), используйте функцию memccpy. Если вы хотите заполнить все байты данной области памяти одинаково, используйте memset.
void *memset(void *s, int c, size_t n);
void *_wmemset(void *s, int c, size_t n);
Заполняет n байтов блока s значением c.

Для сравнения двух областей памяти используется функция memcmp.

int memcmp(const void *s1, const void *s2, size_t n);
Сравнивает n байтов блока s1 с блоком s2.

Правило возращаемого значения:

РезультатВозвращаемое значение
Строка s1 меньше строки s2<0
Строка s1 равна строке s20
Строка s1 больше строки s2>0

Для поиска определенного байта в области памяти, используйте функцию memchr. Как мы увидели, некоторые функции для работы со строками имеют аналоги, работающие с памятью. Назад
Автор и разработчик сайта - Кляус Сергей. Спасибо Форуму на Исходниках.RU за помощь в сборе материалов.
X