it-swarm.com.ru

Как проверить, освобожден ли указатель уже в C?

Я хотел бы проверить, освобожден ли указатель уже или нет. Как мне сделать это с помощью набора компиляторов gnu? 

24
Kitcha

Ты не можешь Чтобы отследить это, можно назначить указатель на 0 или NULL после его освобождения. Однако, как упоминал Фред Ларсон, это никак не влияет на другие указатели, указывающие на то же место.

int* ptr = (int*)malloc(sizeof(int));
free(ptr);
ptr = NULL;
25
Chad

Ты не можешь Просто назначьте NULL после него free, чтобы убедиться, что вы не освободите его дважды (это нормально для free(NULL)).

Еще лучше, если возможно, не писать код, где вы «забыли», что вы уже освободили его.

Правка

Интерпретируя вопрос как как узнать, освобождена ли уже указанная память указателем : вы не можете этого сделать. Вы должны сделать свой собственный бухгалтерский учет.

23
cnicutar

Не существует надежного способа определить, освобожден ли указатель, как прокомментировал Грег, освобожденная память может быть занята другими не относящимися к делу данными, и вы получите неправильный результат.

И действительно, нет стандартного способа проверить, освобожден ли указатель. Тем не менее, glibc имеет функции (mcheck, mprobe), чтобы найти состояние malloc указателя для проверки согласованности кучи , и одна из них - проверить, освобожден ли указатель.

Однако, эти функции в основном используются только для отладки, и они не являются поточно-ориентированными . Если вы не уверены в требованиях, избегайте этих функций. Просто убедитесь, что вы установили пару malloc/free.


Пример http://ideone.com/MDJkj :

#include <stdio.h>
#include <stdlib.h>
#include <mcheck.h>

void no_op(enum mcheck_status status) {}

int main()
{
    mcheck(&no_op);

    void* f = malloc(4);

    printf("%d (should be %d)\n", mprobe(f), MCHECK_OK);
    printf("%d (should be %d)\n", mprobe(f), MCHECK_OK);

    free(f);

    printf("%d (should be %d)\n", mprobe(f), MCHECK_FREE);
    printf("%d (should be %d)\n", mprobe(f), MCHECK_FREE);

    return 0;
}
14
kennytm

Вы можете расширить концепцию присвоения NULL значения указателя, написав макрос, который сделает это за вас. Например:

#define FREE(ptr) do{ \
    free((ptr));      \
    (ptr) = NULL;     \
  }while(0)

Тогда, пока вы убедитесь, что ваш код использует только FREE () и не free (), вы можете быть уверены, что написанный вами код не освобождает одну и ту же память дважды. Конечно, это не делает ничего, чтобы предотвратить множественные вызовы в библиотечные функции, которые освобождают память. И это не делает ничего, чтобы гарантировать, что есть бесплатный для каждого malloc. 

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

4
Brian McFarland

Вы нет, так как вы не можете.

Следите за указателями, которые вы получаете от malloc(), и освобождайте их только один раз.

Если хотите, память не имеет памяти, поэтому она не знает, выделена она или нет. Только диспетчер памяти вашей ОС может сказать вам это (но C не включает в себя какой-либо стандартизированный механизм для запроса этой информации).

2
Kerrek SB

Я знаю, что этот ответ a little bit поздно, но я просто прочитал этот ответ и написал некоторый код в , Проверьте следующее:

Free помещает блок памяти в свой собственный список свободных блоков. Обычно он также пытается объединить смежные блоки в адресном пространстве. Список свободных блоков - это просто циклический список фрагментов памяти, которые, конечно, содержат некоторые данные администратора в начале . Бесплатный список также первое местоположение, malloc ищет новый кусок памяти, когда это необходимо. Сканируется перед вызовом новой памяти из ОС. Когда найден фрагмент, который больше необходимой памяти, он просто делится на две части. Один возвращается вызывающей стороне, другой возвращается в свободный список.

Этот код проверяет только, освобожден ли первый указатель, который был выделен:

int is_freed(void *p)
{
    void * q;
    char p_addr [50];
    char q_addr [50];

    sprintf(p_addr, "%p", p);

    q = malloc (1);
    sprintf(q_addr, "%p", q);
    free (q);

    return ! strcmp(q_addr, p_addr);
}

Я тестировал этот код в HP-UX и Linux Redhat, и он работает, в случае только одного указателя.

0
Mansuro