Когда вы malloc блок, он фактически выделяет немного больше памяти, чем вы просили. Эта дополнительная память используется для хранения информации, такой как размер выделенного блока, и ссылки на следующий свободный / используемый блок в цепочке блоков, а иногда и некоторых «защитных данных», которые помогают системе обнаружить, если вы пишете мимо конец вашего выделенного блока. Кроме того, большинство распределителей округляют общий размер и / или начало вашей части памяти до нескольких байтов (например, в 64-битной системе это может выровнять данные для кратных 64 битам (8 байтов) как доступ к данным с не выровненных адресов может быть более сложным и неэффективным для процессора / шины), поэтому вы можете также получить некоторое заполнение (неиспользуемые байты).
Когда вы освобождаете свой указатель, он использует этот адрес, чтобы найти специальную информацию, которую он добавил в начало (обычно) вашего выделенного блока. Если вы передадите другой адрес, он получит доступ к памяти, содержащей мусор, и, следовательно, его поведение не определено (но чаще всего это приведет к сбою)
Позже, если вы освободите () блок, но не «забудете» свой указатель, вы можете случайно попытаться получить доступ к данным через этот указатель в будущем, и поведение не определено. Может возникнуть любая из следующих ситуаций:
- память может быть помещена в список свободных блоков, поэтому, когда вы обращаетесь к ней, она все равно содержит данные, которые вы там оставили, и ваш код работает нормально.
- распределитель памяти, возможно, отдал (часть) памяти другой части вашей программы, и это, вероятно, перезапишет (некоторые) ваши старые данные, поэтому при чтении вы получите мусор, который может вызвать неожиданное поведение или вылетает из вашего кода. Или вы будете перезаписывать другие данные, в результате чего другая часть вашей программы будет вести себя странно в какой-то момент в будущем.
- память могла быть возвращена операционной системе («страница» памяти, которую вы больше не используете, может быть удалена из вашего адресного пространства, так что больше нет доступной памяти по этому адресу - по сути неиспользованной «дыра» в памяти вашего приложения). Когда ваше приложение попытается получить доступ к данным, произойдет сбой жесткого диска, что приведет к остановке процесса.
Вот почему важно убедиться, что вы не используете указатель после освобождения памяти, на которую он указывает - лучший способ для этого - установить указатель в NULL после освобождения памяти, потому что вы можете легко проверить NULL, и попытка получить доступ к памяти через указатель NULL приведет к плохому, но последовательному поведению, которое намного легче отладить.