¿qué devuelve malloc(0)? [duplicar]


Esta pregunta ya tiene una respuesta aquí:

¿Qué devuelve malloc(0)? ¿Sería la misma respuesta para 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;
}

Salida de linux gcc:

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

La salida cambia cada vez para malloc(0). ¿Es una respuesta estándar? ¿Y por qué alguien estaría interesado en conseguir un pointer, aparte de la investigación académica?

EDITAR:

Si malloc(0) devuelve el puntero ficticio, entonces cómo funciona lo siguiente:

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

EDITAR:

El siguiente código muestra "posible" para cada iteración. ¿Por qué no debería fallar ?

#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;
}
Author: manav m-n, 2010-01-25

10 answers

Otros han respondido cómo funciona malloc(0). Voy a responder a una de las preguntas que usted hizo que no ha sido contestada todavía (creo). La pregunta es acerca de realloc(malloc(0), 0):

¿Qué devuelve malloc(0)? ¿Sería la misma respuesta para realloc(malloc(0),0)?

El estándar dice esto acerca de realloc(ptr, size):

  • si ptr es NULL, se comporta como malloc(size),
  • de lo contrario (ptr no es NULL), desasignará el puntero al objeto antiguo por ptr y devolverá un puntero a un nuevo buffer asignado. Pero si size es 0, C89 dice que el efecto es equivalente a free(ptr). Curiosamente, no puedo encontrar esa declaración en el borrador de C99 (n1256 o n1336). En C89, el único valor sensible a devolver en ese caso sería NULL.

Entonces, hay dos casos:{[67]]}

  • malloc(0) devuelve NULL en una implementación. Entonces su llamada realloc() es equivalente a realloc(NULL, 0). Eso es equivalente a malloc(0) desde arriba (y eso es NULL en este caso).
  • malloc(0) devuelve non - NULL. Entonces, la llamada es equivalente a free(malloc(0)). En este caso, malloc(0) y realloc(malloc(0), 0) son no equivalente.

Tenga en cuenta que hay un caso interesante aquí: en el segundo caso, cuando malloc(0) devuelve no-NULL en caso de éxito, todavía puede devolver NULL para indicar un error. Esto resultará en una llamada como: realloc(NULL, 0), que sería equivalente a malloc(0), que puede o no devolver NULL.

No estoy seguro de si la omisión en C99 es un descuido o si significa que en C99, realloc(ptr, 0) para no-NULL ptr no equivale a free(ptr). Acabo de probar esto con gcc -std=c99, y lo anterior es equivalente a free(ptr).

Edit : Creo que entiendo cuál es tu confusión: {[67]]}

Veamos un fragmento de tu código de ejemplo:

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

Lo anterior no es lo mismo que malloc(0) == realloc(malloc(0), 1024). En la segunda, la llamada malloc() se realiza dos veces, mientras que en la primera, se pasa un puntero asignado previamente a realloc().

Analicemos primero el primer código. Suponiendo que malloc(0) no devuelve NULL en caso de éxito, ptr tiene un valor válido. Cuando lo haces realloc(ptr, 1024), realloc() básicamente le da un nuevo búfer que tiene el tamaño 1024, y el ptr se convierte en inválido. Una implementación conforme puede devolver la misma dirección que la que ya está en ptr. Por lo tanto, su condición if puede devolver verdadero. (Tenga en cuenta, sin embargo, mirando el valor de ptr después de realloc(ptr, 1024) puede ser un comportamiento indefinido.)

Ahora la pregunta que haces: malloc(0) == realloc(malloc(0), 1024). En este caso, vamos a suponer que tanto la malloc(0) en el LHS y RHS devuelve non-NULL. Entonces, están garantizados para ser diferentes. Además, el valor de retorno de malloc() en el LHS no ha sido free()d todavía, por lo que cualquier otro malloc(), calloc(), o realloc() no puede devolver ese valor. Esto significa que si escribiste tu condición como:

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

No verás possible en la salida (a menos que ambos malloc() y realloc() fallen y devuelvan 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;
}

En OS X, mi código no arrojó nada cuando lo ejecuté. En Linux, imprime possible, OK.

 43
Author: Alok Singhal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-26 03:27:06

malloc(0) se define La aplicación en lo que respecta a C99.

De C99 [Sección 7.20.3]

El orden y la contigüidad del almacenamiento asignados por llamadas sucesivas al calloc , las funciones malloc y realloc no están especificadas . El puntero devuelto si la asignación succeeds está alineado adecuadamente para que pueda ser asignado a un puntero a cualquier tipo de objeto y luego se utiliza para acceder a un objeto o una matriz de tales objetos en el espacio asignado (hasta que el espacio esté explícitamente desasignado). La vida útil de un objeto asignado se extiende desde la asignación hasta la cancelación. Cada una de estas asignaciones dará lugar a un indicador de objeto distinto de cualquier otro objeto. El puntero devuelto apunta al inicio (byte más bajo dirección) del espacio asignado. Si el espacio no se puede asignar un puntero nulo es devolver. Si el tamaño del espacio solicitado es cero, el el comportamiento es la implementación- defined: o se devuelve un puntero nulo, o el comportamiento es como si el tamaño fuera valor distinto de cero, excepto que el puntero devuelto no se utilizará para acceder a un objeto.

 32
Author: Prasoon Saurav,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-29 14:35:34

En C89, malloc(0) depende de la implementación - no se si C99 ha arreglado esto o no. En C++, usando:

char * p = new char[0];

Está bien definido - se obtiene un puntero válido, no nulo. Por supuesto, no puede usar el puntero para acceder a lo que apunta sin invocar un comportamiento indefinido.

En cuanto a por qué existe esto, es conveniente para algunos algoritmos, y significa que no necesita ensuciar su código con pruebas para valores cero.

 15
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-25 12:55:58

Estándar C99

Si el espacio no se puede asignar, un se devuelve nullpointer. Si el tamaño del espacio solicitado es cero, el el comportamiento está definido por la implementación: se devuelve un puntero nulo, o el comportamiento es como si el tamaño fuera algún valor distinto de cero, excepto que el el puntero devuelto no se utilizará para acceder a un objeto.

 5
Author: Kornel Kisielewicz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-25 12:50:33

El comp.lang.c FAQ tiene lo siguiente para decir:

El estándar ANSI / ISO dice que puede hacer cualquiera; el comportamiento es definición de implementación (ver pregunta 11.33). Código portátil debe tener cuidado de no llamar a malloc (0), o ser preparado para la posibilidad de un null devolver.

Por lo tanto, probablemente sea mejor evitar usar malloc(0).

 5
Author: unwind,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-25 12:51:51

Véase C99, sección 7.20.3:

Si el tamaño del espacio solicitado es cero, el comportamiento es implementationdefined: o bien un null se devuelve el puntero, o el comportamiento es como si el tamaño fuera algo distinto de cero valor, excepto que el devuelto el puntero no se utilizará para acceder a un objeto.

Esto es válido para las tres funciones de asignación (ie calloc(), malloc() y realloc()).

 3
Author: Christoph,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-25 12:53:29

Un punto del que nadie se preocupó por hablar todavía, en su primer programa es que realloc con longitud 0 es lo mismo que free.

De la página man de Solaris:

La función realloc() cambia el tamaño del bloque apuntado a by ptr a size bytes y devuelve un puntero al bloque (posiblemente movido). El contenido se mantendrá sin cambios hasta el menor de los tamaños nuevos y antiguos. Si ptr es NULL, realloc() se comporta como malloc() para el tamaño especificado. Si size es 0 y ptr no es un puntero nulo, el espacio apuntado está hecho disponible para su posterior asignación por la aplicación, aunque no regresó al sistema. La memoria se devuelve al sistema solo tras la finalización de la solicitud.

Si uno no sabe que puede ser una fuente de mala sorpresa (me pasó a mí).

 3
Author: Patrick Schlüter,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-24 12:07:45

Creo que depende. Comprobé las fuentes de Visual Studio 2005 y vi esto en la función _heap_alloc:

if (size == 0)
    size = 1;

Creo que en muchos casos es posible que desee un puntero válido, incluso cuando se pide cero bytes. Esto se debe a que este comportamiento consistente hace que sea más fácil verificar sus punteros porque: si tiene un puntero no NULO, está bien; si tiene un puntero NULO, probablemente tenga un problema. Es por eso que creo que la mayoría de las implementaciones devolverán un puntero válido, incluso cuando se solicite cero bytes.

 2
Author: Patrick,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-25 12:54:20

Si malloc (0) devuelve el puntero ficticio, entonces cómo funciona lo siguiente:

void *ptr = malloc(0);

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

No se lo que quieres decir con "puntero ficticio". Si malloc(0) devuelve non-NULL, entonces ptr es un puntero válido a un bloque de memoria de tamaño cero. La implementación malloc guarda esta información de una manera específica de la implementación. realloc conoce la forma (específica de la implementación) de averiguar que ptr apunta a un bloque de memoria de tamaño cero.

(Cómo malloc/realloc/free hacer esto es específico de la implementación. Una posibilidad es asignar 4 bytes más de lo solicitado y almacenar el tamaño justo antes del bloque de memoria. En ese caso, ((int *)ptr)[-1] daría el tamaño del bloque de memoria, que es 0. Nunca debe hacer esto desde su código, es solo para uso de realloc y free).

 0
Author: user9876,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-25 13:37:17

Hemos implementado estructuras malloc para código embebido con un encabezado (y un trailer opcional). El encabezado puede contener información adicional de depuración, como el controlador de tareas que lo asignó. Además, me gusta tener banderas / límites como 0xA5A5A5A5, y 0x5A5A5A5A para ayudar a detectar si alguien en algún lugar ha sobrescrito los límites de su asignación de memoria(s). Al mantener listas de bloques libres y usados, también se puede verificar periódicamente la integridad del montón y evitar operaciones (como free() de bloques no asignados memoria) que podría hacer que las cosas "exploten".

 0
Author: Juhan Leemet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-02-14 19:59:15