Вопрос

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

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

#include<stdio.h>
#include<malloc.h>
int main()
{
        printf("%p\n", malloc(0));
        printf("%p\n", 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).Это стандартный ответ?И почему кто-то может быть заинтересован в получении такого указателя, кроме академических исследований?

Редактировать:

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

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

Редактировать:

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

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

        int i;
        void *ptr;
        printf("Testing using BRUTE FORCE\n");
        for (i=0; i<65000; i++)
        {
                ptr = malloc(0);
                if (ptr == realloc(ptr, 1024))
                        printf("Iteration %d: possible\n", i);
                else
                {
                        printf("Failed for iteration %d\n", i);
                        break;
                }
        }
        return 0;
}
Это было полезно?

Решение

Другие отвечали, как 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) возвращает не-NULL.Тогда вызов эквивалентен free(malloc(0)).В данном случае, malloc(0) и realloc(malloc(0), 0) являются не эквивалент.

Обратите внимание, что здесь есть интересный случай:во втором случае, когда malloc(0) возвращает не-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 возвращает не-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.

От С99 [Раздел 7.20.3]

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

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

char * p = new char[0];

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

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

Стандарт C99

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

В часто ЗАДАВАЕМЫЕ ВОПРОСЫ по comp.lang.c имеет следующее чтобы сказать:

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

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

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

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

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

Один момент, о котором еще никто не позаботился поговорить в вашей первой программе, заключается в том, что realloc с длиной 0 - это то же самое, что и free.

со страницы руководства Solaris:

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top