Чи вільний (ptr), де ptr - NULL пошкоджена пам'ять?


112

Теоретично я можу це сказати

free(ptr);
free(ptr); 

це пошкодження пам’яті, оскільки ми звільняємо вже звільнену пам’ять.

Але що робити, якщо

free(ptr);
ptr=NULL;
free(ptr); 

Оскільки ОС буде вести себе невизначено, я не можу отримати фактичний теоретичний аналіз цього щодо того, що відбувається. Що б я не робив, це пошкодження пам’яті чи ні?

Чи вільне звільнення вказівника NULL?


1
не впевнений у вільному стандарті C, але в C ++ delete (NULL) цілком дійсний, тому, мабуть, повинен бути і безкоштовний (NULL).
Priyank Bolia

14
@Pryank: delete NULLне вірно в C ++. Видалення може бути застосоване до значень нульового вказівника конкретного типу, але не до NULL. delete (int*) NULLє законним, але ні delete NULL.
AnT

тому це означає, що якщо вказівник вказує на NULL безкоштовно, нічого не виконує. це означає !!!!!! щоразу в нашому кодуванні, якщо ви хочете звільнити пам'ять, можна просто замінити вільний (ptr) на ptr = NULL?
Віджай

3
Ні. Якщо ptrвказує на пам'ять, і ви не дзвоните freeна неї, пам'ять просочиться. Встановивши його NULLпросто втрачає ручку на пам'ять і протікає. Якщо це ptr сталосяNULL , дзвінок free- це бездіяльність.
GManNickG

1
@benjamin: А? Що змусило вас зробити висновок про те , що ви можете замінити free(ptr)з ptr = NULL. Ніхто нічого подібного не сказав.
ANT

Відповіді:


224

7.20.3.2 freeФункція

Конспект

#include <stdlib.h> 
void free(void *ptr); 

Опис

freeФункція викликає простір , на який вказує ptrна звільнятися, тобто зробив для подальшого розподілу. Якщо ptrнульовий вказівник, жодних дій не відбувається.

Див. ISO-IEC 9899 .

Але, дивлячись на різні бази коду в дикій природі, ви помітите, що люди іноді роблять:

if (ptr)
  free(ptr);

Це тому, що деякі C час виконання (я точно пам’ятаю, що це було в PalmOS) може вийти з ладу під час звільнення NULLпокажчика.

Але в наш час я вважаю, що можна з упевненістю припустити free(NULL), що це нос, згідно зі стандартом.


29
Ні, ptr = NULL - це спосіб заміни безкоштовно (ptr), обидва абсолютно різні
Prasoon Saurav

7
НІ, це означає, free(ptr)де ptrnull не має побічних ефектів. Але в будь-якому випадку, кожна пам'ять, виділена з використанням malloc()або calloc()повинна бути звільнена після цього,free()
Грегорі Пакош

4
ptr = NULL гарантує, що навіть якщо ви випадково зателефонуєте безкоштовно (ptr), ваша програма не буде за замовчуванням.
Prasoon Saurav

2
Зауважте, що хоча стандарт C говорить про те, що він не працює, це не означає, що кожна C-бібліотека обробляє це так. Я бачив збої безкоштовно (NULL), тому краще уникати в першу чергу виклику безкоштовних.
Дерик

6
@WereWolfBoy він має на увазі уникнути free(NULL)тестування вказівника проти NULLдзвінкаfree()
Грегорі Пакош

22

Усі версії бібліотеки С, що відповідають стандартам, розглядають безкоштовно (NULL) як неоперативний.

Це означає, що свого часу існували деякі версії безкоштовних, які б вийшли з ладу безкоштовно (NULL), тому ви можете побачити деякі методи оборонного програмування, які рекомендують:

if (ptr != NULL)
    free(ptr);

8
-1 [потрібне цитування]. Зміна стилю коду через деяку теорію реалізації архаїчної чужої мови є поганою ідеєю.
Томаш

41
@Tomas - Я ніколи не рекомендував змінювати стиль, я просто пояснив, чому ви все ще можете побачити цю рекомендацію в деяких стилях.
R Самуель Клачко

5
@Tomas 3BSD ( winehq.org/pipermail/wine-patches/2006-O жовтня/031544.html ) та PalmOS для двох (2-а рука для обох).
Дуглас Лідер

7
@Tomas: проблема була в таких речах, як версія 7 Unix. Коли я вчився, безкоштовно (xyz), де xyz == NULL був рецептом миттєвої катастрофи на машині, на якій я дізнався (ICL Perq під управлінням PNX, який базувався на версії 7 Unix з деякими додатками System III). Але я давно не кодував це.
Джонатан Леффлер

2
Мережеве програмне забезпечення також виходить з ладу NULL ... (просто налагоджено аварію на ньому ...)
Кальмарій

13

Якщо ptr - NULL, жодна операція не виконується.

говорить документація.


Ви маєте на увазі, що вільний нічого не виконає?
Віджай

2
Бенджамін, саме це означає. Що б ви очікували від його виконання, якщо він знає про недійсність аргументу?
Майкл Крелін - хакер

12

Пам’ятаю, працював на PalmOS, де free(NULL)розбився.


4
Цікаво - те, що робить другу платформу (після 3BSD), яка виходить з ладу.
Дуглас Лідер

2
Якщо я добре пам'ятаю, на Palm стандартна бібліотека C не існувала. Натомість був в основному непідтримуваний файл заголовка, який відображав стандартні виклики бібліотеки через SDK Palm OS. Багато речей діяли несподівано. Поломка NULLбула однією з великих відмінностей панелі інструментів Palm порівняно зі стандартною бібліотекою.
Стівен Фішер

8
free(ptr);
ptr=NULL;
free(ptr);/*This is perfectly safe */

Ви можете безпечно видалити покажчик NULL. У цьому випадку жодна операція не буде виконуватися. Іншими словами, free () не робить нічого за вказівником NULL.


8

Рекомендоване використання:

free(ptr);
ptr = NULL;

Побачити:

man free

     The free() function deallocates the memory allocation pointed to by ptr.
     If ptr is a NULL pointer, no operation is performed.

Якщо встановити покажчик NULLпісля free()того, як ви зможете зателефонувати free()на нього ще раз, жодна операція не буде виконуватися.


3
Це також допоможе виявити налагодження segfault за допомогою налагоджувача. Очевидно, що segfault у p-> do () з p = 0 - це хтось, хто використовує звільнений покажчик. Менш видно, коли ви бачите p = 0xbfade12 в налагоджувачі :)
нейро

6

free(NULL)є абсолютно законним як на C, так delete (void *)0і delete[] (void *)0є законним у C ++.

До речі, звільнення пам'яті двічі зазвичай спричиняє певну помилку виконання, тому вона нічого не пошкоджує.


2
delete 0не є законним для C ++. deleteявно вимагає вираження типу вказівника. Легально застосовувати deleteдо введеного значення нульового вказівника, але не до 0(а не до NULL).
AnT

1
Ви не можете видалити void*жодне з них: P Які деструктори (и) повинні працювати?
GManNickG

1
@GMan: Ви можете видалити void *, якщо це нульовий покажчик.
AnT

Гаразд, досить справедливо. Я забув, що ми маємо справу лише з нульовим.
GManNickG

зазвичай нічого не псує, але не гарантує. ASLR робить це досить малоймовірним, але все ж не неможливим: buf1=malloc(X); free(buf1);buf2=malloc(X);free(buf1); - ось, якщо вам не пощастило, buf2 отримав таку саму адресу, що і buf1, і ви випадково випустили buf1 двічі, тож на 2-му звільненні від buf1 ви фактично звільнили buf2 мовчки, не застосовуючи при цьому будь-яка (неминуча) помилка / аварія / що завгодно. (але ви все ще отримаєте аварію наступного разу, коли ви спробуєте використовувати buf2 - і цей сценарій є дуже малоймовірним, якщо ви працюєте на ASLR)
hanshenrik

3

free(ptr)Це збереження в C, якщо ptrце NULL, однак, те, що більшість людей не знає, це те, що вони NULLне повинні дорівнювати 0. У мене є гарний приклад старої школи: на C64, за адресою 0, є IO-порт. Якщо ви написали програму на C, що отримує доступ до цього порту, вам знадобиться вказівник, значення якого дорівнює 0. У відповідній бібліотеці C потрібно було б розрізняти 0 і NULLпотім.

З повагою.


Цікавий факт, зловив мене зненацька. Змусило мене почувати себе змушеним здійснити подорож навколо NULL питань / відповідей вказівника.
членистоногий


-3

ptr вказує на деяке місце пам'яті, скажімо, 0x100.

Коли ви звільнені (ptr), ви в основному дозволяєте використовувати менеджер пам'яті 0x100 для використання в інших видах діяльності або процесу, простіше кажучи, це розподіл ресурсів.

Коли ви робите ptr = NULL, ви вказуєте ptr на нове місце (не турбуйтеся про те, що таке NULL). Таким чином ви втратили дані про пам'ять 0x100. Це те, що є витоком пам'яті.

Тому не доцільно використовувати ptr = NULL на дійсному ptr.

Натомість ви можете зробити безпечну перевірку за допомогою:

якщо (ptr! = NULL) {безкоштовно (ptr);}

Коли ви звільняєте (ptr), коли ptr вже вказує на NULL, він не виконує жодної операції. Отже, безпечно це робити.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.