что возвращает 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 ответов


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

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

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

  • если ptr и NULL, он ведет себя как malloc(size),
  • в противном случае (ptr не NULL), это освобождает старый указатель объекта на ptr и возвращает указатель на новый выделенный буфер. Но если ... --14--> равно 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) для некурящихNULL ptr не эквивалентно free(ptr). Я только что пробовал это с gcc -std=c99, и вышеизложенное эквивалентно free(ptr).

редактировать: кажется, я понимаю, в чем ваша путаница:

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

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()буду еще, так любой другой 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) is Реализации что касается C99.

С C99 [раздел 7.20.3]

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


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

char * p = new char[0];

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

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


стандарт C99

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


на comp.ленг.C FAQ и следующее сказать:

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

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


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

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

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


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

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

на realloc() функция изменяет размер указанного блока кptr to size байт и возвращает указатель на (возможно переехали) блок. Содержание будет неизменным до меньший из новых и старых размеров. Если ptr is NULL, realloc() ведет себя как malloc() для указанного размера. Если size is 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 является допустимым указателем на блок памяти нулевого размера. The malloc реализация сохраняет эту информацию в реализации определенным способом. realloc знает (реализации) способ выяснить, что ptr очки к блоку памяти нулевого размера.

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


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