что возвращает malloc(0)? [дубликат]


этот вопрос уже есть ответ здесь:

Что значит malloc(0) возвращает? Будет ли ответ таким же для realloc(malloc(0),0) ?

#include<stdio.h>
#include<malloc.h>
int main()
{
        printf("%pn", malloc(0));
        printf("%pn", realloc(malloc(0), 0));
        return 0;
}

выход из linux gcc:

manav@manav-workstation:~$ gcc -Wall mal.c
manav@manav-workstation:~$ ./a.out
0x9363008
(nil)
manav@manav-workstation:~$

выход постоянно меняется каждый раз для malloc(0). Это стандартная ответ? И почему кто-то заинтересован в получении такого указателя, кроме академических исследований?

EDIT:

если malloc(0) возвращает фиктивный указатель, а затем как работает следующее:

int main()
{
    void *ptr = malloc(0);
    printf("%pn", realloc(ptr, 1024));
    return 0;
}

EDIT:

следующий код выводит "возможно" для каждой итерации. Почему бы ему не потерпеть неудачу ?

#include<stdio.h>
#include<malloc.h>
int main()
{

        int i;
        void *ptr;
        printf("Testing using BRUTE FORCEn");
        for (i=0; i<65000; i++)
        {
                ptr = malloc(0);
                if (ptr == realloc(ptr, 1024))
                        printf("Iteration %d: possiblen", i);
                else
                {
                        printf("Failed for iteration %dn", i);
                        break;
                }
        }
        return 0;
}
10 52

10 ответов:

другие ответили как malloc(0) строительство. Я отвечу на один из вопросов, которые вы задали, который еще не получил ответа (я думаю). Речь идет о realloc(malloc(0), 0):

что значит malloc(0) вернуться? Будет ли ответ таким же для realloc(malloc(0),0)?

стандарт говорит о realloc(ptr, size):

  • если ptr и NULL, он ведет себя как malloc(size),
  • в противном случае (ptr не NULL), это освобождает старый указатель объекта на ptr и возвращает указатель на новый выделенный буфер. Но если size равно 0, C89 говорит, что эффект эквивалентен free(ptr). Интересно, что я не могу найти это утверждение в проекте C99 (n1256 или n1336). В C89 единственным разумным значением для возврата в этом случае будет NULL.

Итак, есть два случая:

  • malloc(0) возвращает NULL на реализацию. Тогда ваш realloc() вызов эквивалентен realloc(NULL, 0). Что эквивалентно malloc(0) сверху (и это NULL в данном случае).
  • malloc(0) возвращает non -NULL. Тогда вызов эквивалентен free(malloc(0)). В этом случае malloc(0) и realloc(malloc(0), 0) are не эквивалентны.

обратите внимание, что есть интересный случай: во втором случае, когда malloc(0) возвращает non -NULL на успех, он все еще может вернуться NULL, чтобы указать отказ. Это приведет к вызову типа:realloc(NULL, 0), который будет эквивалентно malloc(0), который может или не может вернуться NULL.

я не уверен, является ли упущение в C99 оплошностью или это означает, что в C99,realloc(ptr, 0) для некурящихNULLptr не эквивалентно free(ptr). Я только что попробовал это с gcc -std=c99, и вышеизложенное эквивалентно free(ptr).

Edit: мне кажется, я понимаю, в чем ваше замешательство:

давайте посмотрим на фрагмент из вашего примера кода:

ptr = malloc(0);
if (ptr == realloc(ptr, 1024))

в выше это не то же самое, что malloc(0) == realloc(malloc(0), 1024). Во втором,malloc() вызов выполняется дважды, тогда как в первом случае вы передаете ранее выделенный указатель на realloc().

давайте сначала проанализируем первый код. Предполагая, что malloc(0) не отвечает NULL на ptr имеет допустимое значение. Когда вы делаете realloc(ptr, 1024),realloc() в основном дает вам новый буфер, который имеет размер 1024, а ptr становится недействительным. Соответствующая реализация может возвращать тот же адрес, что и тот уже в ptr. Итак, ваш if условие может вернуть true. (Обратите внимание, однако, глядя на значение ptr после realloc(ptr, 1024) может быть неопределенное поведение.)

теперь вопрос, который вы задаете:malloc(0) == realloc(malloc(0), 1024). В этом случае предположим, что оба malloc(0) на LHS и RHS возвращает non -NULL. Тогда они гарантированно будут разными. Кроме того, возвращаемое значение malloc() на LHS не было free()d еще, так что любой другой malloc(),calloc() или realloc() может не вернуться это значение. Это означает, что если вы написали свое состояние как:

if (malloc(0) == realloc(malloc(0), 1024)
    puts("possible");

вы не увидите possible на выходе (если оба malloc() и realloc() сбой и возвращать NULL).

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

int main(void)
{
    void *p1;
    void *p2;

    p1 = malloc(0);
    p2 = realloc(p1, 1024);
    if (p1 == p2)
        puts("possible, OK");

    /* Ignore the memory leaks */
    if (malloc(0) == realloc(malloc(0), 1024))
        puts("shouldn't happen, something is wrong");
    return 0;
}

на OS X мой код ничего не выводил, когда я его запускал. В Linux он печатает possible, OK.

malloc(0) и Реализации что касается C99.

С C99 [раздел 7.20.3]

порядок и смежность хранения, выделенные последовательными вызовами calloc, функции malloc и realloc не указаны. Указатель возвращается, если выделение succeeds соответствующим образом выровнен так, чтобы он мог быть назначен указателю на любой тип объекта а затем используется для доступа к такой объект или массив таких объектов в выделенном пространстве (пока пространство не будет явно освобождено). Время жизни выделенного объекта увеличивается от выделения до освобождения. Каждое такое распределение должно давать указатель на объект непересекающийся от любого другого объекта. Указатель возвращает точки начала (младший байт адрес) выделенного пространства. Если пространство не может быть выделена, указатель null возвращенный. Если размер запрошенное пространство равно нулю, поведение является реализацией- определено: либо возвращается нулевой указатель, либо поведение выглядит так, как если бы размер был некоторым ненулевое значение, за исключением того, что возвращается указатель не должен использоваться для доступа к объекту.

в C89 malloc (0) зависит от реализации - я не знаю, исправил ли C99 это или нет. В C++, используя:

char * p = new char[0];

хорошо определен - вы получаете действительный, ненулевой указатель. Конечно, вы не можете использовать указатель для доступа к тому, на что он указывает, не вызывая неопределенное поведение.

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

стандарт C99

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

на комп.ленг.с чаво и следующее сказать:

стандарт ANSI / ISO говорит, что он может сделать что-либо; поведение реализация определена (см. вопрос 11.33). Переносимый код должен либо позаботиться о том, чтобы не вызывать malloc(0), либо быть подготовлено к возможности нулевого значения возвращаться.

поэтому, вероятно, лучше избегать использования malloc(0).

см. C99, раздел 7.20.3:

Если размер запрашиваемого пространства равен ноль, поведение implementationdefined: либо null возвращается указатель или поведение это как если бы размер был какой-то ненулевой значение, за исключением того, что возвращается указатель не должен использоваться для доступа к объект.

Это справедливо для всех трех функций выделения (т. е. calloc(),malloc() и realloc()).

один момент, о котором еще никто не хотел говорить, в вашей первой программе это realloc с длиной 0 это то же самое, что и free.

С man-страницы Solaris:

The realloc() функция изменяет размер указанного блока купить ptr до size байт и возвращает указатель на (возможно переехали) блок. Содержание будет неизменным вплоть до меньший из новых и старых размеров. Если ptr - это NULL,realloc() ведет себя как malloc() для указанного размера. Если size и 0 и ptr не является нулевым указателем, пространство, на которое указано, Сделано доступно для дальнейшего распределения приложением, хотя не вернулся в систему. Память возвращается в систему только по окончании подачи заявки.

если кто-то не знает, что это может быть источником плохого сюрприза (случилось со мной).

Я думаю, что это зависит. Я проверил источники Visual Studio 2005 и увидел это в функции _heap_alloc:

if (size == 0)
    size = 1;

Я думаю, что во многих случаях вы можете захотеть действительный указатель, даже при запросе нулевых байтов. Это связано с тем, что такое согласованное поведение упрощает проверку указателей, потому что: если у вас есть ненулевой указатель, это нормально; если у вас есть нулевой указатель, у вас, вероятно, есть проблема. Вот почему я думаю, что большинство реализаций вернет действительный указатель, даже когда запрашиваю ноль байт.

если malloc (0) возвращает фиктивный указатель, то как работает следующее:

void *ptr = malloc(0);

printf("%p\n", realloc(ptr, 1024));

я не знаю, что вы подразумеваете под "манекен указатель". Если malloc(0) возвращает ненулевое значение, затем ptr является допустимым указателем на блок памяти нулевого размера. Элемент malloc реализация сохраняет эту информацию в реализации определенным способом. realloc знает (реализации) способ выяснить, что ptr очки к блоку памяти нулевого размера.

(как malloc/realloc/free сделать это зависит от конкретной реализации. Одна из возможностей состоит в том, чтобы выделить 4 байта больше, чем требуется, и сохранить размер непосредственно перед блоком памяти. В таком случае, ((int *)ptr)[-1] даст размер блока памяти, который составляет 0. Вы никогда не должны делать это из кода, это только для использования realloc и free).

мы реализовали структуры malloc для встроенного кода с заголовком (и дополнительным трейлером). Заголовок может содержать дополнительную отладочную информацию, например дескриптор задачи, который его выделил. Кроме того, мне нравится иметь флаги/границы, такие как 0xA5A5A5A5, и 0x5A5A5A5A, чтобы помочь обнаружить, если кто-то где-то перезаписал границы их выделения памяти. Сохраняя списки свободных и используемых блоков, можно также периодически проверять целостность кучи и предотвращать операции (например, free () of unallocated память), что может привести к тому, что вещи "взорвутся".