Ваш анализ внешне близок в некоторых отношениях, но неверен.
p
и r
определены как указатели в первом выражении main()
. Они не создаются динамически. Они определены как переменные продолжительности автоматического хранения с main()
, поэтому они перестают существовать, когда (фактически if, в случае вашей программы) возвращается main()
.
Это не p
создается и освобождается. malloc()
динамически выделяет память и, в случае успеха, возвращает указатель, который идентифицирует эту динамически выделенную память (или указатель NULL
, если динамическое выделение не удается), но не инициализирует ее. Значение, возвращаемое malloc()
, (после преобразования в указатель на int
, который требуется в C++) присваивается p
.
Затем ваш код печатает значение p
.
(Я выделил следующий абзац курсивом, так как вернусь к нему ниже).
Следующий оператор выводит значение *p
. Это означает доступ к значению по адресу, на который указывает p
. Однако эта память не инициализирована, поэтому результатом обращения к *p
является неопределенное поведение. С вашей реализацией (компилятором и библиотекой) в настоящее время это приводит к «значению мусора», которое затем печатается. Однако такое поведение не гарантируется — на самом деле оно может сделать что угодно. Различные реализации могут давать разные результаты, такие как ненормальное завершение работы (сбой вашей программы), переформатирование жесткого диска или [на практике гораздо менее вероятно] воспроизведение песни "Crash" примитивов через громкоговорители вашего компьютера.
После вызова free(p)
ваш код проходит аналогичную последовательность с указателем r
.
Присваивание *p = 100
имеет неопределенное поведение, так как p
содержит значение, возвращенное первым вызовом malloc()
, но оно было передано free()
. Итак, что касается вашей программы, существование этой памяти больше не гарантируется.
Первый оператор cout
после этого обращается к *p
. Поскольку p
больше не существует (будучи переданным free()
), это дает неопределенное поведение.
Второй оператор cout
после этого обращается к *r
. Эта операция имеет неопределенное поведение по той же причине, что я описал в выделенном курсивом абзаце выше (для p
, как это было тогда).
Обратите внимание, однако, что в вашем коде было пять случаев неопределенного поведения. Когда происходит хотя бы один случай неопределенного поведения, все ставки на возможность предсказать поведение вашей программы прекращаются. В вашей реализации результаты выводятся на печать p
и r
с одинаковым значением (поскольку malloc()
возвращает одно и то же значение 0x2f7630
в обоих случаях), в обоих случаях печатается значение мусора, а затем (после оператора *p = 100
) печатается значение 100
при печати *p
и *r
.
Однако ни один из этих результатов не гарантирован. Причина отсутствия гарантии заключается в том, что значение «неопределенного поведения» в стандарте C++ заключается в том, что стандарт не описывает ограничений на то, что разрешено, поэтому реализация может делать что угодно. Ваш анализ может быть правильным для вашей конкретной реализации, в конкретное время, когда вы скомпилировали, скомпоновали и запустили свой код. Это может быть даже правильно на следующей неделе, но неверно через месяц после обновления вашей стандартной библиотеки (например, применения исправлений ошибок). Вероятно, это неверно для других реализаций.
Напоследок пара незначительных моментов.
Во-первых, ваш код неполный и даже не скомпилируется в том виде, в котором вы его описали. В обсуждении выше я предположил, что вашему коду на самом деле предшествует
#include <iostream>
#include <cstdlib>
using namespace std;
Во-вторых, malloc()
и free()
— это функции из стандартной библиотеки. Они не операторы.
person
Peter
schedule
14.08.2016
free()
- это не оператор, это функция. Это не влияет на ваше объяснение или ответ, но иногда в C++ стоит понять разницу. - person Steve Jessop   schedule 14.08.2016