Otros han respondido cómo malloc(0)
obras. Responderé una de las preguntas que hiciste y que aún no ha sido respondida (creo). La pregunta es sobre realloc(malloc(0), 0)
:
¿Qué significa malloc(0)
¿devolver? ¿La respuesta sería la misma para realloc(malloc(0),0)
? ?
El estándar dice esto sobre realloc(ptr, size)
:
- si
ptr
esNULL
, se comporta comomalloc(size)
, - de lo contrario (
ptr
no esNULL
), desasigna el antiguo puntero de objeto porptr
y devuelve un puntero a un nuevo búfer asignado. Pero sisize
es 0, C89 dice que el efecto es equivalente afree(ptr)
. Curiosamente, no puedo encontrar esa declaración en el borrador C99 (n1256 o n1336). En C89, el único valor sensato para devolver en ese caso seríaNULL
.
Entonces, hay dos casos:
malloc(0)
devuelveNULL
en una implementación. Entonces turealloc()
llamada es equivalente arealloc(NULL, 0)
. Eso es equivalente amalloc(0)
desde arriba (y eso esNULL
en este caso).malloc(0)
devuelve noNULL
. Entonces, la llamada es equivalente afree(malloc(0))
. En este caso,malloc(0)
yrealloc(malloc(0), 0)
son no equivalente.
Tenga en cuenta que aquí hay un caso interesante:en el segundo caso, cuando malloc(0)
devuelve no NULL
en caso de éxito, aún puede devolver NULL
para indicar el fracaso. 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 si la omisión en C99 es un descuido o si significa que en C99, realloc(ptr, 0)
para no NULL
ptr
no es equivalente a free(ptr)
. Acabo de probar esto con gcc -std=c99
, y lo anterior es equivalente a free(ptr)
.
Editar :Creo que entiendo cuál es tu confusión:
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 el segundo, el malloc()
la llamada se realiza dos veces, mientras que en la primera, está pasando un puntero previamente asignado a realloc()
.
Analicemos primero el primer código. Asumiendo malloc(0)
no devuelve NULL
en caso de éxito, ptr
tiene un valor válido. Cuando haces realloc(ptr, 1024)
, realloc()
básicamente te da un nuevo búfer que tiene el tamaño 1024 y el ptr
se vuelve inválido. Una implementación conforme puede devolver la misma dirección que la que ya está en ptr
. Entonces, tu if
la condición puede volver verdadera. (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, supongamos que tanto el malloc(0)
en LHS y RHS devuelve no 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()
puede que no devuelva ese valor. Esto significa que si escribió su 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()
falla y devuelve 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 generó nada cuando lo ejecuté. En Linux, imprime possible, OK
.
malloc(0)
está definido para la implementación en lo que respecta a C99.
Desde C99 [Sección 7.20.3]
El orden y la contigüidad del almacenamiento asignado por llamadas sucesivas a las funciones calloc, malloc y realloc no están especificados . El puntero devuelto si la asignación tiene éxito se alinea adecuadamente para que pueda asignarse a un puntero a cualquier tipo de objeto y luego usarse para acceder a dicho objeto o una matriz de tales objetos en el espacio asignado (hasta que el espacio se desasigna explícitamente). El tiempo de vida de un objeto asignado se extiende desde la asignación hasta la desasignación. Cada asignación producirá un puntero a un objeto disjunto de cualquier otro objeto. El puntero devolvió puntos al inicio (la dirección de byte más baja) del espacio asignado. Si no se puede asignar el espacio, se devuelve un puntero nulo. Si el tamaño del espacio solicitado es cero, el comportamiento está definido por la implementación :se devuelve un puntero nulo o el comportamiento es como si el tamaño fuera un valor distinto de cero, excepto que el puntero devuelto no se utilizará para acceder a un objeto.
En C89, malloc(0) depende de la implementación; no sé si C99 solucionó esto o no. En C++, usando:
char * p = new char[0];
está bien definido: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é esto existe, es conveniente para algunos algoritmos y significa que no necesita ensuciar su código con pruebas para valores cero.