Понимание поведения висячего указателя в этом случае

У меня есть указатель, и по умолчанию он содержит NULL, затем он ждет некоторого события и получает значение, если событие происходит, позже я освобождаю указатель в другом месте но даже после освобождения указателя я не делаю его NULL, поэтому он по-прежнему ссылается на одно и то же место в памяти, и я знаю, что следующий вызов malloc может выделить эту память фрагмент на какой-то другой запрос памяти!

pointer_type *p = NULL;
while (process_get_wakeup(//some logic//)) { 
        while ((qelem = (void*)process_dequeue(//some logic//)) != NULL) {
           p = (pointer_type *)qelem;
        }
        .
        .
        //goes into a loop of calls where free(p) is also done!
        .
        .
        //Printing value of p as %p gives this : 0xFF00000000

РЕДАКТИРОВАТЬ: Я уже знаю, что это не то, как мы должны это делать, и я не могу ожидать сохранения того же значения, которое может быть использовано для чего-то другого сейчас, но я хочу знать, почему я вижу только определенное значение p!

Имеет ли это значение: 0xFF00000000 какое-либо особое значение?


person SUMIT KUMAR SINGH    schedule 11.09.2018    source источник
comment
Возможный дубликат Почему мой указатель не равен нулю после освобождения?   -  person Yunnosch    schedule 11.09.2018
comment
Не делайте никаких предположений о значении указателя, возвращаемом malloc. Единственным специальным значением указателя, которое может быть возвращено malloc, является NULL.   -  person Jabberwocky    schedule 11.09.2018
comment
@Jabberwocky Я действительно признаю вашу точку зрения, но тогда какова может быть цель этого компилятора, чтобы всегда иметь это значение в указателе, который до сих пор обращался к внеконтекстной памяти, поскольку я не сделал его NULL явно?   -  person SUMIT KUMAR SINGH    schedule 11.09.2018
comment
Я думаю, вам следует прочитать главу, посвященную динамическому распределению памяти и указателям, в учебнике по C. После free(p) значение p не меняется, но p никуда не указывает, или, другими словами, указывает на какую-то память, которая вам больше не принадлежит, и вы больше не можете разыменовывать p . Так работает язык C.   -  person Jabberwocky    schedule 11.09.2018


Ответы (2)


Напротив, указатель не сохраняет свое значение после free.

Стандарт C говорит, что как только объект становится freed или, в более общем случае, его время жизни заканчивается, значения всех указателей, указывающих на объект, становятся неопределенными, и использование такого неопределенного значения может привести к неопределенным поведение, даже если он просто печатал значение. То, что он выглядит так, как будто он сохраняет свою первоначальную ценность, никоим образом не гарантируется.

Это позволяет компилятору C выполнять оптимизацию внутри вашей функции. Например, если он использовал один регистр ЦП для сохранения значения p, то после вызова free(p) компилятор знает, что этот регистр теперь можно использовать для чего-то другого, например для хранения результатов промежуточных вычислений другие операции, и его значение не нужно сохранять, пока ему не будет присвоено новое значение.


Что касается адреса памяти двух разных объектов, совпадающих - это возможно, если они не живы одновременно. Один объект будет иметь постоянный адрес на протяжении всей жизни. Что происходит после его жизни, не уточняется. malloc часто реализуется как список свободных блоков, а самый последний блок freed, скорее всего, будет повторно использован первым.

person Antti Haapala    schedule 11.09.2018
comment
p не обращается к действительному доступу к памяти, поскольку память помечена как свободная с помощью бесплатного вызова для нее, но тогда вы говорите, что оптимизация компилятора имеет то же значение (0xFF00000000) для оборванных указателей, когда память, которую они r к указанию обращается какой-либо действительный указатель? - person SUMIT KUMAR SINGH; 11.09.2018
comment
@SUMITKUMARSINGH ах нет, я говорю, что висячий указатель не должен сохранять свое значение, если компилятор может это доказать. - person Antti Haapala; 11.09.2018
comment
Правильно! Меня беспокоит, почему всегда отображается одно и то же значение, поскольку я ожидал случайных ненужных значений. - person SUMIT KUMAR SINGH; 11.09.2018
comment
@SUMITKUMARSINGH Указатель становится неопределенным после того, как вы free, а это означает, что вы не можете ожидать, что он будет чем-либо - NULL, нежелательным или сохранит тот же адрес - после того, как вы освободитесь. В ту секунду, когда вы позвоните бесплатно, вы должны перестать заботиться о том, на что он указывает. - person Kcvin; 11.09.2018
comment
@Kcvin: В качестве общего расширения многие реализации, особенно те, которые предназначены для низкоуровневого программирования или самостоятельного размещения, позволяют выполнять некоторые операции с указателями, цель которых была освобождена. Такие реализации также, как правило, например, позволяют реализации проверять, переместил ли realloc блок, и предполагают, что если новый и старый указатели идентичны, не будет необходимости повторно вычислять указатели, которые идентифицируют местоположения внутри блока, что может сэкономить время, если realloc() сжимает блок и, таким образом, вряд ли переместит его. - person supercat; 04.10.2018
comment
@supercat это хорошо, но он не переносим и не соответствует стандарту C. - person Kcvin; 10.10.2018
comment
@Kcvin: Вы читали опубликованное «Обоснование стандарта C»? «Хотя он стремился дать программистам возможность писать действительно переносимые программы, комитет C89 не хотел принуждать программистов писать переносимые программы, чтобы предотвратить использование C в качестве «ассемблера высокого уровня»: возможность писать специфичный для машины код. является одной из сильных сторон C.' Реализации, которые не будут использоваться для целей, требующих семантической мощности «высокоуровневого ассемблера», не обязаны поддерживать такую ​​семантику, но авторы стандарта прямо признали... - person supercat; 10.10.2018
comment
... существование и полезность реализаций, которые явно не намеревались сделать язык непригодным для использования в целях, требующих такой семантики. Имейте в виду, что хотя Стандарт не требует, чтобы реализация поддерживала всю семантику, необходимую для написания функций, таких как malloc(), на языке C, многие реализации используют библиотеки, которые фактически написаны на языке C; Было бы практически невозможно реализовать полезную функцию free(), если бы она не могла сделать ничего полезного с указателем (например, сделать пространство доступным для будущего запроса malloc(). - person supercat; 10.10.2018
comment
@supercat Обратите внимание, что в стандарте конкретно упоминаются как размещенные, так и автономные среды - в автономной среде имена malloc, realloc и т. д. не будут зарезервированы. - person Antti Haapala; 10.10.2018
comment
@AnttiHaapala: Некоторые компиляторы, такие как gcc, сами не включают библиотечные функции, но ожидают, что пользователи предоставят их, при этом делая предположения о том, что они делают (предполагая, например, что printf("Hello\n"); можно заменить на puts("Hello");, и многие встроенные компиляторы включают много библиотечных функций, но недостаточно, чтобы квалифицироваться как размещенные реализации. Я думаю, что намерение Стандарта состоит в том, что в реализациях, которые не определяют библиотечные функции, пользовательский код должен иметь возможность это делать, но Стандарт действительно мог бы использовать здесь некоторую ясность. Например.. . - person supercat; 10.10.2018
comment
... может быть полезно сказать, что в таких реализациях, если код выполняет malloc, а затем free, и компилятор может видеть, что указатель никогда не будет разыменован за пределами своего диапазона (и не будет подвергаться коду, который мог бы выполнить so), он не должен рассматривать временное получение через malloc/free как заметно отличающееся от других форм временного получения, таких как выделение стека, даже если реальная реализация побочных эффектов библиотеки может иметь наблюдаемые побочные эффекты [например. создание журнала «отладки» запросов на выделение]. - person supercat; 10.10.2018
comment
@supercat will allow some operations to be performed with pointers whose target has been released ... Независимо от распространенных расширений и того, что должно быть переносимым или нет, разве здравый смысл не подскажет, не использовать указатель после его освобождения? - person Kcvin; 12.10.2018
comment
@Kcvin: Печать значений освобожденных указателей может быть полезна, если кто-то пытается отладить самого себя диспетчер памяти. Кроме того, бывают случаи, когда для наибольшей эффективности программе потребуется версия realloc(), которая просто оставит старый блок действительным, если нет необходимости его перемещать. На некоторых малоизвестных платформах arealloc() может возвращать указатель, который побитно идентичен старому, но, тем не менее, делает другие указатели на блок непригодными для использования. Следовательно, Стандарт рассматривает realloc() так, как будто он всегда освобождает старый блок... - person supercat; 12.10.2018
comment
...за исключением случаев, когда это не удается. Если код выполняет malloc() с выделением памяти, которое, как ожидается, будет больше, чем ему нужно, а затем использует realloc(), чтобы сократить выделение до фактически используемого пространства, то, если коду не требуется совместимость с малоизвестными платформами, он должна быть возможность свести к минимуму избыточные операции в общем случае, когда блок остается на месте [ИМХО, должна была быть realloc-подобная функция, которая, когда это возможно, изменяла бы размер блока без его перемещения и возвращала новый размер, но его нет]. - person supercat; 12.10.2018
comment
Вы всегда можете заранее скопировать указатель на uintptr_t;) - person Antti Haapala; 12.10.2018

позже я освобождаю указатель в другом месте? Убедитесь, что вы освобождаете p только тогда, когда ему назначается адрес динамической памяти, иначе это приведет к неопределенному поведению.

p = NULL; /* now it's points to NULL */
p = malloc(SIZE); /* malloc() may give same previews memory location or may not */

Из стандарта C, раздел 6.2.4

Время жизни объекта — это часть выполнения программы, в течение которой для него гарантированно резервируется память. Объект существует, имеет постоянный адрес и сохраняет свое последнее сохраненное значение на протяжении всей своей жизни. Если на объект ссылаются за пределами его времени жизни, поведение не определено. Значение указателя становится неопределенным, когда объект, на который он указывает (или только что прошедший), достигает конца своего времени существования.

А также

Я не могу рассчитывать на сохранение того же значения, которое может быть использовано для чего-то другого сейчас?

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

person Achal    schedule 11.09.2018