Чи вільний (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.