Respuestas:
Según las especificaciones, malloc (0) devolverá "un puntero nulo o un puntero único que se puede pasar con éxito a free ()".
Básicamente, esto le permite no asignar nada, pero aún así pasar la variable "artista" a una llamada a free () sin preocupaciones. A efectos prácticos, es prácticamente lo mismo que hacer:
artist = NULL;
El estándar C (C17 7.22.3 / 1) dice:
Si el tamaño del espacio solicitado es cero, el comportamiento está definido por la implementación: o 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.
Por lo tanto, malloc(0)
podría devolver NULL
o un puntero válido que no puede ser desreferenciado . En cualquier caso, es perfectamente válido invocarlo free()
.
Realmente no creo que malloc(0)
tenga mucho uso, excepto en los casos en que malloc(n)
se llama en un bucle, por ejemplo, y n
podría ser cero.
Mirando el código en el enlace, creo que el autor tenía dos conceptos erróneos:
malloc(0)
devuelve un puntero válido siempre , yfree(0)
es malo.Entonces, se aseguró de que artist
y otras variables siempre tuvieran algún valor "válido" en ellas. El comentario dice tanto: // these must always point at malloc'd data
.
malloc(0)
devuelve un puntero válido, malloc()
devolver NULL
significa "falla" siempre, y 0
ya no es un caso especial, que es más consistente.
malloc
falla para obtener memoria están definidas por la implementación, una implementación podría simplemente definir que las asignaciones de tamaño 0 son siempre insatisfactorias ( ENOMEM
), y ahora malloc(0)
devolver 0 (con errno==ENOMEM
) es consistente. :-)
realloc
devolver un puntero malloc(0)
? ¿Puede usted realloc((char*)NULL)
?
El comportamiento de malloc (0) es específico de la implementación. La biblioteca puede devolver NULL o tener el comportamiento malloc normal, sin memoria asignada. Haga lo que haga, debe estar documentado en alguna parte.
Por lo general, devuelve un puntero que es válido y único, pero NO debe desreferenciarse. También tenga en cuenta que PUEDE consumir memoria a pesar de que en realidad no asignó nada.
Es posible reasignar un puntero malloc (0) no nulo.
Sin embargo, tener un malloc (0) literalmente no es de mucha utilidad. Se usa principalmente cuando una asignación dinámica es de cero bytes y no le importó validarla.
malloc()
debe mantener "información de mantenimiento" en algún lugar (este tamaño del bloque asignado, por ejemplo, y otros datos auxiliares). Entonces, si malloc(0)
no regresa NULL
, usará memoria para almacenar esa información, y si no free()
d, constituirá una pérdida de memoria.
malloc()
devolverá o devolverá NULL
.
malloc(0)
. Sin embargo, en la misma implementación de la biblioteca C estándar, realloc(ptr, 0)
libera ptr
y devuelve NULL.
Hay una respuesta en otra parte de esta página que comienza "malloc (0) devolverá una dirección de memoria válida y cuyo rango dependerá del tipo de puntero al que se le está asignando memoria". Esta declaración es incorrecta (no tengo suficiente reputación para comentar esa respuesta directamente, por lo que no puedo poner este comentario directamente debajo).
Hacer malloc (0) no asignará automáticamente la memoria del tamaño correcto. La función malloc no sabe a qué está enviando su resultado. La función malloc se basa puramente en el número de tamaño que le da como argumento. Debe hacer malloc (sizeof (int)) para obtener suficiente almacenamiento para contener un int, por ejemplo, no 0.
malloc(0)
no tiene ningún sentido para mí, a menos que el código se base en un comportamiento específico de la implementación. Si el código está destinado a ser portátil, entonces debe tener en cuenta el hecho de que un retorno NULL de malloc(0)
no es un error. Entonces, ¿por qué no simplemente asignar NULL a de artist
todos modos, ya que ese es un resultado exitoso válido y es menos código, y no hará que sus programadores de mantenimiento se tomen tiempo para resolverlo?
malloc(SOME_CONSTANT_THAT_MIGHT_BE_ZERO)
o malloc(some_variable_which_might_be_zero)
tal vez podría tener sus usos, aunque nuevamente debe tener especial cuidado de no tratar una devolución NULL como un error si el valor es 0, pero se supone que un tamaño 0 está bien.
Hay muchas respuestas a medias verdaderas por aquí, así que aquí están los hechos concretos. La página de manual de malloc()
dice:
Si el tamaño es 0, entonces malloc () devuelve NULL o un valor de puntero único que luego se puede pasar con éxito a free ().
Eso significa que no hay absolutamente ninguna garantía de que el resultado de malloc(0)
sea único o no NULL. La única garantía la proporciona la definición de free()
, nuevamente, esto es lo que dice la página de manual:
Si ptr es NULL, no se realiza ninguna operación.
Entonces, cualquier cosa que malloc(0)
regrese, se puede pasar con seguridad free()
. Pero también puede hacerlo un NULL
puntero.
En consecuencia, escribir no artist = malloc(0);
es mejor que escribir artist = NULL;
malloc(0)
podría devolver, digamos, 0x1, y free()
podría tener una verificación de caso especial de 0x1 tal como lo ha hecho para 0x0.
NULL
o un puntero único". en su lugar, "un puntero nulo o un puntero al espacio asignado". No hay un requisito único . OTOH, devolver un valor especial no único puede interrumpir el código que cuenta con valores únicos. Quizás una pregunta de caso de esquina para SO.
man
también puede documentar la forma definida por la implementación utilizada en * nix. En este caso no es así, pero todavía no es una fuente canónica para el general C.
Por qué no deberías hacer esto ...
Dado que el valor de retorno de malloc depende de la implementación, puede obtener un puntero NULL o alguna otra dirección. Esto puede terminar creando desbordamientos de búfer de pila si el código de manejo de errores no verifica tanto el tamaño como el valor devuelto, lo que genera problemas de estabilidad (fallas) o incluso peores problemas de seguridad.
Considere este ejemplo, donde el acceso adicional a la memoria a través de la dirección devuelta dañará el montón si el tamaño es cero y la implementación devuelve un valor no NULO.
size_t size;
/* Initialize size, possibly by user-controlled input */
int *list = (int *)malloc(size);
if (list == NULL) {
/* Handle allocation error */
}
else {
/* Continue processing list */
}
Vea esta página de codificación segura de los estándares de codificación CERT, donde tomé el ejemplo anterior para leer más.
Es cierto que nunca había visto esto antes, esta es la primera vez que veo esta sintaxis, se podría decir, un caso clásico de exceso de funciones. Junto con la respuesta de Reed, me gustaría señalar que hay algo similar, que parece una función sobrecargada realloc
:
realloc(foo, size);
. Cuando pasas un puntero no NULL y un tamaño de cero para reasignar, la reasignación se comporta como si hubieras llamado a free (…)realloc(foo, size);
,. Cuando pasa un puntero NULL y el tamaño no es cero, realloc se comporta como si hubiera llamado malloc (…)Espero que esto ayude, Saludos cordiales, Tom.
malloc (0) devolverá NULL o un puntero válido que se puede pasar correctamente a free. Y aunque parece que la memoria a la que apunta es inútil o no se puede escribir o leer, eso no siempre es cierto. :)
int *i = malloc(0);
*i = 100;
printf("%d", *i);
Esperamos una falla de segmentación aquí, pero sorprendentemente, ¡imprime 100! Es porque malloc realmente pide una gran cantidad de memoria cuando llamamos a malloc por primera vez. Cada llamada a malloc después de eso, usa la memoria de ese gran trozo. Solo después de que termina esa gran parte, se solicita una nueva memoria.
Uso de malloc (0): si se encuentra en una situación en la que desea que las llamadas a malloc posteriores sean más rápidas, llamar a malloc (0) debería hacerlo por usted (excepto en los casos extremos).
*i
no se bloquee en su caso, pero de todos modos es un comportamiento indefinido. ¡Cuidado con los demonios nasales!
malloc(0)
que no se menciona. En aquellas implementaciones en las que devuelve un valor no NULO, especialmente en una compilación DEBUG, es probable que asigne MÁS de lo que solicitó y le da el puntero para pasar su encabezado interno. Esto le permite tener una idea del uso real de la memoria si lo obtiene antes y después de una serie de asignaciones. por ejemplo: void* before = malloc(0); ... void* after = malloc(0); long long total = after - before;
o algo así.
malloc(0)
. ¿Podría decirnos a qué capítulo se refiere también? Proporcionar una cotización exacta también sería bueno.
En Windows:
void *p = malloc(0);
asignará un búfer de longitud cero en el montón local. El puntero devuelto es un puntero de montón válido.malloc
en última instancia, llama HeapAlloc
utilizando el montón de tiempo de ejecución de C predeterminado que luego llama RtlAllocateHeap
, etc.free(p);
utiliza HeapFree
para liberar el búfer de longitud 0 en el montón. No liberarlo resultaría en una pérdida de memoria.En realidad, es bastante útil y (obviamente en mi humilde opinión), el comportamiento permitido de devolver un puntero NULL está roto. Un puntero dinámico es útil no solo por lo que apunta, sino también por el hecho de que su dirección es única. Devolver NULL elimina esa segunda propiedad. Todos los programas mallocs I incrustados (de hecho con bastante frecuencia) tienen este comportamiento.
No estoy seguro, de acuerdo con un código fuente de malloc aleatorio que encontré, una entrada de 0 da como resultado un valor de retorno de NULL. Así que es una forma loca de establecer el puntero del artista en NULL.
http://www.raspberryginger.com/jbailey/minix/html/lib_2ansi_2malloc_8c-source.html
Aquí está el análisis después de ejecutar con la herramienta de verificación de memoria valgrind.
==16740== Command: ./malloc0
==16740==
p1 = 0x5204040
==16740==
==16740== HEAP SUMMARY:
==16740== in use at exit: 0 bytes in 0 blocks
==16740== total heap usage: 2 allocs, 2 frees, 1,024 bytes allocated
==16740==
==16740== All heap blocks were freed -- no leaks are possible
y aquí está mi código de muestra:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
//int i;
char *p1;
p1 = (char *)malloc(0);
printf("p1 = %p\n", p1);
free(p1);
return 0;
}
De forma predeterminada, se asignan 1024 bytes. Si aumento el tamaño de malloc, los bytes asignados aumentarán en 1025 y así sucesivamente.
De acuerdo con la respuesta de Reed Copsey y la página de manual de malloc, escribí algunos ejemplos para probar. Y descubrí que malloc (0) siempre le dará un valor único. Mira mi ejemplo:
char *ptr;
if( (ptr = (char *) malloc(0)) == NULL )
puts("Got a null pointer");
else
puts("Got a valid pointer");
La salida será "Tiene un puntero válido", lo que significa que ptr
no es nulo.
malloc(0)
devolverá una dirección de memoria válida y cuyo rango dependerá del tipo de puntero al que se le está asignando memoria. También puede asignar valores al área de memoria, pero esto debe estar dentro del rango del tipo de puntero que se esté utilizando. También puede liberar la memoria asignada. Explicaré esto con un ejemplo:
int *p=NULL;
p=(int *)malloc(0);
free(p);
El código anterior funcionará bien en un gcc
compilador en una máquina Linux. Si tiene un compilador de 32 bits, puede proporcionar valores en el rango de enteros, es decir, -2147483648 a 2147483647. Lo mismo se aplica a los caracteres también. Tenga en cuenta que si se cambia el tipo de puntero declarado, el rango de valores cambiará independientemente del malloc
encasillado, es decir
unsigned char *p=NULL;
p =(char *)malloc(0);
free(p);
p
tomará un valor de 0 a 255 de char ya que se declara un int sin signo.
malloc()
no sabe nada sobre el elenco (que en realidad es completamente superfluente en C). Desreferenciar el valor de retorno de malloc(0)
invocará un comportamiento indefinido.
Solo para corregir una falsa impresión aquí:
artist = (char *) malloc(0);
nunca jamás volverá NULL
; no es lo mismo que artist = NULL;
. Escribir un programa simple y comparar artist
con NULL
. if (artist == NULL)
es falso y if (artist)
es verdadero.