¿qué devuelve malloc(0)? [duplicar]
Esta pregunta ya tiene una respuesta aquí:
- ¿cuál es el punto en malloc(0)? 16 respuestas
¿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;
}
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 pararealloc(malloc(0),0)
?
El estándar dice esto acerca de realloc(ptr, size)
:
- si
ptr
esNULL
, se comporta comomalloc(size)
, - de lo contrario (
ptr
no esNULL
), desasignará el puntero al objeto antiguo porptr
y devolverá un puntero a un nuevo buffer asignado. Pero sisize
es 0, C89 dice que el efecto es equivalente afree(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íaNULL
.
Entonces, hay dos casos:{[67]]}
-
malloc(0)
devuelveNULL
en una implementación. Entonces su llamadarealloc()
es equivalente arealloc(NULL, 0)
. Eso es equivalente amalloc(0)
desde arriba (y eso esNULL
en este caso). -
malloc(0)
devuelve non -NULL
. Entonces, la llamada es equivalente afree(malloc(0))
. En este caso,malloc(0)
yrealloc(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
.
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.
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.
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.
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)
.
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()
).
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 byptr
asize
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. Siptr
esNULL
,realloc()
se comporta comomalloc()
para el tamaño especificado. Sisize
es0
yptr
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í).
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.
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
).
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".
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