Чтобы понять основную причину этих ограничений, давайте предположим, что компилятор не дает ошибку компиляции для того, чтобы не именовать имя файла так же, как имя общедоступного класса.
Предположим, что существует пакет A
A / \ file1.java file2.java
file1.java
package A; class file1 {public static void main (String args []) {}} public class file3 {public static void main (String args []) {}}
Теперь, когда мы знаем, что a открытый класс также можно получить за пределами пакета, теперь он станет обязанностью разработчика сделать его доступным для внешнего мира. Давайте посмотрим, как:
Предположим, что пакет A содержит только файлы Java (без файлов классов), а некоторый класс вне пакета A пытается получить доступ к файлу с открытым классом3, компилятор сначала попытается найти file3.class (недоступно ), тогда он попытается найти file3.java (недоступно). Таким образом, хотя класс file3 носит публичный характер, он не виден во внешнем мире. Поэтому, если компилятор устанавливает ограничение на то, что если файл содержит открытый класс, его следует назвать таким же, как имя открытого класса, тогда проблема выше может быть решена, и разработчику не придется думать об экспонировании открытого класса во внешний мир .
Компилятор также устанавливает ограничение на то, что в каждом Java-файле должен быть один открытый класс, так что к любому публичному классу может быть доступен внешний мир.
Поскольку использование недопустимого указателя вызывает неопределенное поведение. И это означает, что поведение ... хорошо ... undefined. Это не обязано сбой.
Почему курица может продолжать бегать и прыгать, несмотря на то, что ее голову отрубают? Обратите внимание, что это не всегда всегда ; некоторые цыплята могут перестать двигаться немедленно, а другие могут продолжать работать в течение нескольких месяцев . Когда это происходит, это происходит, потому что это происходит. Означает ли это, что мы должны вырезать наши домашние животные?
Как разрезание наших питомцев с головой, использование освобожденной памяти - это плохая идея. Это не означает, что это приведет к отрицательным результатам; ваша программа может продолжать работать как ожидалось на вашем компьютере, в то время как if (fubar)
(где fubar является вашим недопустимым указателем) может быть достаточно, чтобы вызвать сбой вашей программы в других реализациях .
Эта идея свободы реализации для определения (или не) поведения формально известна как неопределенное поведение ; поведение не определено, поскольку стандарт C, набор документов, определяющий поведение C-реализации, не определяет поведение . Поэтому, как и резка наших домашних животных, мы должны избегать всех неопределенного поведения.
Когда вы вызываете free(phead)
, память phead
указывает на освобождение, но значение phead
остается нетронутым, делая указатель phead
a болтающимся . Доступ к освобожденной памяти создает неопределенное поведение.
Хорошей практикой является назначение указателя NULL
указателю, когда вы освободите память, на которую он указывает:
free(phead);
phead = NULL;
NULL
указателю решит все проблемы в мире, и все программисты будут счастливы когда-либо. Я просто говорю, что это хорошая практика, как избежать создания дополнительных висячих указателей.
– LihO
15 March 2013 в 14:37
NULL
на head
, он не будет указывать на память free()
d ...
– user
15 March 2013 в 14:45
NULL
после памяти free()
d вполне разумно и предназначено. Иногда это не только хорошая практика, но и важная вещь.
– LihO
15 March 2013 в 17:08
Поскольку память по-прежнему отображается в ваш процесс, но не выделяется. В программе C есть два уровня управления памятью: во-первых, ядро дает вам страницы, на которые вы можете писать. Если для процесса требуется больше памяти, которую он отобразил, он должен запросить больше из ядра (sbrk). Это происходит в больших кусках, поэтому malloc разрезает его на куски для вас, запрашивая больше страниц по мере необходимости, но используя, где возможно, память, уже выделенную для программы. free не может вернуть страницу до тех пор, пока все используемые ею распределения не будут освобождены.
Таким образом, нарушения доступа к памяти, которые ядро дает вам (SIGSEGV), довольно грубые и не могут собрать большую часть памяти ошибки, только вещи, которые являются фатальными с точки зрения ядра. Вы можете удалять данные отслеживания malloc, читать их до конца большинства распределений и после многих бесплатных и т. Д.
Однако никогда не выполняйте ошибки памяти. Запустите приложение с valgrind, в котором используется очень строгая виртуальная машина, чтобы проверить все ошибки и раздавить их немедленно.
Поскольку освобождение памяти (указатель) просто возвращает эту память в пул свободной памяти. Память не просто исчезает, и ее содержимое не очищается до тех пор, пока эта память не будет выделена снова и не будет записана.
Таким образом, очень легко получить доступ к памяти после ее освобождения. Просто не очень хорошая идея, как вы можете себе представить, потому что она может быть выделена в любое время и изменена.