¿Cuál es la diferencia entre hacer:
ptr = (char **) malloc (MAXELEMS * sizeof(char *));
o:
ptr = (char **) calloc (MAXELEMS, sizeof(char*));
¿Cuándo es una buena idea usar calloc sobre malloc o viceversa?
ptr = calloc(MAXELEMS, sizeof(*ptr));
¿Cuál es la diferencia entre hacer:
ptr = (char **) malloc (MAXELEMS * sizeof(char *));
o:
ptr = (char **) calloc (MAXELEMS, sizeof(char*));
¿Cuándo es una buena idea usar calloc sobre malloc o viceversa?
ptr = calloc(MAXELEMS, sizeof(*ptr));
Respuestas:
calloc()le da un búfer con inicialización cero, mientras malloc()deja la memoria sin inicializar.
Para asignaciones grandes, la mayoría de las callocimplementaciones en sistemas operativos convencionales obtendrán páginas conocidas a cero del sistema operativo (por ejemplo, a través de POSIX mmap(MAP_ANONYMOUS)o Windows VirtualAlloc), por lo que no es necesario escribirlas en el espacio del usuario. Así es como normal mallocobtiene más páginas del sistema operativo también; callocsolo aprovecha la garantía del sistema operativo.
Esto significa que la callocmemoria todavía puede ser "limpia" y asignada perezosamente, y copiar y escribir en una página física compartida de ceros en todo el sistema. (Suponiendo un sistema con memoria virtual).
Algunos compiladores incluso pueden optimizar malloc + memset (0) en calloc para usted, pero debe usar calloc explícitamente si desea que la memoria se lea como 0.
Si nunca va a leer la memoria antes de escribirla, úsela mallocpara que pueda (potencialmente) darle memoria sucia de su lista libre interna en lugar de obtener nuevas páginas del sistema operativo. (O en lugar de poner a cero un bloque de memoria en la lista libre para una asignación pequeña).
Las implementaciones integradas de callocpueden dejarlo callocsolo en memoria cero si no hay sistema operativo, o no es un sistema operativo multiusuario sofisticado que pone a cero las páginas para detener las fugas de información entre procesos.
En Linux incorporado, malloc podría mmap(MAP_UNINITIALIZED|MAP_ANONYMOUS), que solo está habilitado para algunos núcleos integrados porque es inseguro en un sistema multiusuario.
callocno es necesariamente más caro, ya que el sistema operativo puede hacer algunos trucos para acelerarlo. Sé que FreeBSD, cuando obtiene un tiempo de CPU inactivo, lo usa para ejecutar un proceso simple que simplemente da vueltas y pone a cero los bloques de memoria desasignados, y marca los bloques, por lo tanto, los procesos con un indicador. Entonces, cuando lo hace calloc, primero trata de encontrar uno de esos bloques pre-cero y simplemente dárselo, y lo más probable es que encuentre uno.
Una diferencia menos conocida es que en sistemas operativos con asignación de memoria optimista, como Linux, el puntero devuelto por mallocno está respaldado por memoria real hasta que el programa realmente lo toca.
callocde hecho, toca la memoria (escribe ceros en ella) y, por lo tanto, se asegurará de que el sistema operativo respalde la asignación con RAM (o intercambio) real. Esta es también la razón por la que es más lento que malloc (no solo tiene que ponerlo a cero, el sistema operativo también debe encontrar un área de memoria adecuada posiblemente intercambiando otros procesos)
Vea, por ejemplo, esta pregunta SO para una mayor discusión sobre el comportamiento de malloc
callocNo es necesario escribir ceros. Si el bloque asignado se compone principalmente de nuevas páginas cero proporcionadas por el sistema operativo, puede dejarlas intactas. Por supuesto, esto requiere callocestar sintonizado con el sistema operativo en lugar de una función de biblioteca genérica malloc. O, un implementador podría hacer calloccomparar cada palabra contra cero antes de ponerla a cero. Esto no ahorraría tiempo, pero evitaría ensuciar las nuevas páginas.
dlmallocimplementaciones similares omiten memsetsi el fragmento se obtuvo a través mmapde nuevas páginas anónimas (o equivalentes). Por lo general, este tipo de asignación se utiliza para fragmentos más grandes, comenzando en 256k más o menos. No conozco ninguna implementación que haga la comparación contra cero antes de escribir cero aparte de la mía.
omalloctambién se salta el memset; callocno necesita tocar ninguna página que la aplicación ya no use (caché de página), nunca. Sin embargo, las callocimplementaciones extremadamente primitivas difieren.
Una ventaja que a menudo se pasa por alto calloces que (implementaciones conformes de) ayudará a protegerlo contra vulnerabilidades de desbordamiento de enteros. Comparar:
size_t count = get_int32(file);
struct foo *bar = malloc(count * sizeof *bar);
vs.
size_t count = get_int32(file);
struct foo *bar = calloc(count, sizeof *bar);
El primero podría resultar en una pequeña asignación y desbordamientos del búfer posteriores, si countes mayor que SIZE_MAX/sizeof *bar. Este último fallará automáticamente en este caso ya que no se puede crear un objeto tan grande.
Por supuesto, es posible que tenga que estar atento a las implementaciones no conformes que simplemente ignoran la posibilidad de desbordamiento ... Si esto es una preocupación en las plataformas a las que apunta, tendrá que hacer una prueba manual de desbordamiento de todos modos.
char es un desbordamiento, sino más bien una conversión definida por la implementación al asignar el resultado nuevamente a un objeto. char
size_tes de 64 bits, así que no hay problema", esa es una forma errónea de pensar que conducirá a errores de seguridad. size_tes un tipo abstracto que representa tamaños, y no hay razón para pensar que el producto arbitrario de un número de 32 bits y un size_t(nota: ¡ sizeof *baren principio podría ser mayor que 2 ^ 32 en una implementación de C de 64 bits!) size_t.
La documentación hace que el calloc se vea como malloc, que simplemente inicializa cero la memoria; ¡Esta no es la principal diferencia! La idea de calloc es eliminar la semántica de copia en escritura para la asignación de memoria. Cuando asigna memoria con calloc, todo se asigna a la misma página física que se inicializa a cero. Cuando cualquiera de las páginas de la memoria asignada se escribe en una página física, se asigna. Esto se usa a menudo para crear tablas hash ENORMES, por ejemplo, ya que las partes de hash que están vacías no están respaldadas por ninguna memoria adicional (páginas); felizmente apuntan a la página única con inicialización cero, que incluso se puede compartir entre procesos.
Cualquier escritura en la dirección virtual se asigna a una página, si esa página es la página cero, se asigna otra página física, la página cero se copia allí y el flujo de control se devuelve al proceso del cliente. Esto funciona de la misma manera que funcionan los archivos mapeados en memoria, la memoria virtual, etc., utiliza paginación.
Aquí hay una historia de optimización sobre el tema: http://blogs.fau.de/hager/2007/05/08/benchmarking-fun-with-calloc-and-zero-pages/
No hay diferencia en el tamaño del bloque de memoria asignado. callocsimplemente llena el bloque de memoria con un patrón físico de cero bits. En la práctica, a menudo se supone que los objetos ubicados en el bloque de memoria asignado calloctienen un valor inicial como si se inicializaran con literales 0, es decir, los enteros deberían tener el valor de 0variables de punto flotante - valor de0.0 punteros, el valor de puntero nulo apropiado , y así.
Sin embargo, desde el punto de vista pedante, calloc(así como memset(..., 0, ...)) solo se garantiza que inicializará correctamente (con ceros) objetos de tipo unsigned char. No se garantiza que todo lo demás se inicialice correctamente y puede contener la llamada representación de trampa , lo que provoca un comportamiento indefinido. En otras palabras, para cualquier tipo que no seaunsigned char el patrón de cero bits mencionado anteriormente, podría representar un valor ilegal, la representación de trampa.
Más tarde, en uno de los estándares técnicos de Corrigenda a C99, el comportamiento se definió para todos los tipos enteros (lo cual tiene sentido). Es decir, formalmente, en el lenguaje C actual solo puede inicializar tipos enteros con calloc(y memset(..., 0, ...)). Usarlo para inicializar cualquier otra cosa en un caso general conduce a un comportamiento indefinido, desde el punto de vista del lenguaje C.
En la práctica, callocfunciona, como todos sabemos :), pero depende de usted si desea usarlo (teniendo en cuenta lo anterior). Personalmente prefiero evitarlo por completo, usarlo mallocy realizar mi propia inicialización.
Finalmente, otro detalle importante es que callocse requiere para calcular internamente el tamaño final del bloque , multiplicando el tamaño del elemento por el número de elementos. Al hacerlo, callocdebe estar atento a un posible desbordamiento aritmético. Resultará en una asignación fallida (puntero nulo) si el tamaño de bloque solicitado no se puede calcular correctamente. Mientras tanto, su mallocversión no intenta buscar desbordamiento. Asignará una cantidad de memoria "impredecible" en caso de que ocurra un desbordamiento.
memset(p, v, n * sizeof type);un problema porque n * sizeof typepuede desbordarse. Supongo que necesitaré usar un for(i=0;i<n;i++) p[i]=v;bucle para código robusto.
nexiste una matriz con elementos donde un elemento tiene el tamaño sizeof type, entonces n*sizeof typeno puede desbordarse, porque el tamaño máximo de cualquier objeto debe ser menor que SIZE_MAX.
SIZE_MAX, pero no hay matrices aquí. El puntero devuelto desde calloc()puede apuntar a la memoria asignada que excede SIZE_MAX. Muchas implementaciones limitan el producto de los 2 argumentos calloc()a SIZE_MAX, sin embargo, la especificación C no impone ese límite.
de un artículo Benchmarking divertido con calloc () y cero páginas en el blog de Georg Hager
Al asignar memoria usando calloc (), la cantidad de memoria solicitada no se asigna de inmediato. En cambio, todas las páginas que pertenecen al bloque de memoria están conectadas a una sola página que contiene todos los ceros por algo de magia MMU (enlaces a continuación). Si tales páginas solo se leen (lo que era cierto para las matrices b, cyd en la versión original del punto de referencia), los datos se proporcionan desde la página cero única, que, por supuesto, cabe en la memoria caché. Esto en cuanto a los núcleos de bucle de memoria. Si se escribe una página (no importa cómo), se produce un error, la página "real" se asigna y la página cero se copia en la memoria. Esto se llama copia en escritura, un enfoque de optimización bien conocido (que incluso he enseñado varias veces en mis conferencias de C ++). Después de esto,
calloc es generalmente malloc+memset a 0
En general, es un poco mejor usar malloc+memsetexplícitamente, especialmente cuando está haciendo algo como:
ptr=malloc(sizeof(Item));
memset(ptr, 0, sizeof(Item));
Eso es mejor porque sizeof(Item)es conocido por el compilador en tiempo de compilación y el compilador en la mayoría de los casos lo reemplazará con las mejores instrucciones posibles para poner a cero la memoria. Por otro lado, si memsetestá sucediendo en calloc, el tamaño del parámetro de la asignación no se compila en el calloccódigo y a memsetmenudo se llama real , que típicamente contendría código para llenar byte por byte hasta un límite largo, que ciclo para llenar memoria en sizeof(long)trozos y, finalmente, byte a byte llenan el espacio restante. Incluso si el asignador es lo suficientemente inteligente como para llamar a algunosaligned_memset , seguirá siendo un bucle genérico.
Una excepción notable sería cuando está haciendo malloc / calloc de una gran parte de la memoria (algunos power_of_two kilobytes) en cuyo caso la asignación se puede hacer directamente desde el núcleo. Dado que los núcleos del sistema operativo normalmente pondrán a cero toda la memoria que regalan por razones de seguridad, calloc lo suficientemente inteligente podría devolverla sin una reducción a cero adicional. Una vez más, si solo está asignando algo que sabe que es pequeño, es mejor que use malloc + memset en cuanto al rendimiento.
calloc()más lento que malloc(): la multiplicación por el tamaño. calloc()es necesario usar una multiplicación genérica (si size_tes de 64 bits, incluso la muy costosa operación de 64 bits * 64 bits = 64 bits) mientras que el malloc () a menudo tendrá una constante de tiempo de compilación.
struct foo { char a,b,c; };. callocsiempre es mejor que malloc+ memset, si siempre va a borrar toda la mallocregión ed. calloctambién tiene una comprobación cuidadosa pero eficiente para el desbordamiento int en los elementos de tamaño *.
Diferencia 1:
malloc() generalmente asigna el bloque de memoria y se inicializa el segmento de memoria.
calloc() asigna el bloque de memoria e inicializa todo el bloque de memoria a 0.
Diferencia 2:
Si considera la malloc()sintaxis, solo tomará 1 argumento. Considere el siguiente ejemplo a continuación:
data_type ptr = (cast_type *)malloc( sizeof(data_type)*no_of_blocks );
Por ejemplo: si desea asignar 10 bloques de memoria para el tipo int,
int *ptr = (int *) malloc(sizeof(int) * 10 );
Si considera la calloc()sintaxis, tomará 2 argumentos. Considere el siguiente ejemplo a continuación:
data_type ptr = (cast_type *)calloc(no_of_blocks, (sizeof(data_type)));
Ej: si desea asignar 10 bloques de memoria para el tipo int e Inicializar todo eso a CERO,
int *ptr = (int *) calloc(10, (sizeof(int)));
Semejanza:
Ambos malloc()y calloc()devolverán void * de forma predeterminada si no están escritos en tipo.!
Hay dos diferencias
Primero, está en el número de argumentos. malloc()toma un solo argumento (se requiere memoria en bytes), mientras que calloc()necesita dos argumentos.
En segundo lugar, malloc()no inicializa la memoria asignada, mientras que calloc()inicializa la memoria asignada a CERO.
calloc()asigna un área de memoria, la longitud será el producto de sus parámetros. callocllena la memoria con CERO y devuelve un puntero al primer byte. Si no puede encontrar suficiente espacio, devuelve un NULLpuntero.Sintaxis: ptr_var=(cast_type *)calloc(no_of_blocks , size_of_each_block);
es decirptr_var=(type *)calloc(n,s);
malloc()asigna un solo bloque de memoria de TAMAÑO REQUSTADO y devuelve un puntero al primer byte. Si no puede localizar la cantidad de memoria requerida, devuelve un puntero nulo.Sintaxis: ptr_var=(cast_type *)malloc(Size_in_bytes);
la malloc()función toma un argumento, que es el número de bytes para asignar, mientras que la calloc()función toma dos argumentos, uno es el número de elementos y el otro es el número de bytes para asignar para cada uno de esos elementos. Además, calloc()inicializa el espacio asignado a ceros, mientras malloc()que no.
La calloc()función que se declara en el <stdlib.h>encabezado ofrece un par de ventajas sobre la malloc()función.
malloc()y calloc()son funciones de la biblioteca estándar de C que permiten la asignación dinámica de memoria, lo que significa que ambas permiten la asignación de memoria durante el tiempo de ejecución.
Sus prototipos son los siguientes:
void *malloc( size_t n);
void *calloc( size_t n, size_t t)
Existen principalmente dos diferencias entre los dos:
Comportamiento: malloc()asigna un bloque de memoria, sin inicializarlo, y leer el contenido de este bloque dará como resultado valores basura. calloc(), por otro lado, asigna un bloque de memoria y lo inicializa a ceros, y obviamente leer el contenido de este bloque dará como resultado ceros.
Sintaxis: malloc()toma 1 argumento (el tamaño que se asignará) y calloc()toma dos argumentos (número de bloques que se asignarán y tamaño de cada bloque).
El valor de retorno de ambos es un puntero al bloque de memoria asignado, si tiene éxito. De lo contrario, se devolverá NULL indicando el error de asignación de memoria.
Ejemplo:
int *arr;
// allocate memory for 10 integers with garbage values
arr = (int *)malloc(10 * sizeof(int));
// allocate memory for 10 integers and sets all of them to 0
arr = (int *)calloc(10, sizeof(int));
La misma funcionalidad que calloc()se puede lograr usando malloc()y memset():
// allocate memory for 10 integers with garbage values
arr= (int *)malloc(10 * sizeof(int));
// set all of them to 0
memset(arr, 0, 10 * sizeof(int));
Tenga en cuenta que malloc()se usa preferiblemente calloc()ya que es más rápido. Si desea inicializar a cero los valores, use calloc()en su lugar.
Una diferencia aún no mencionada: límite de tamaño
void *malloc(size_t size)solo puede asignar hasta SIZE_MAX.
void *calloc(size_t nmemb, size_t size); puede asignar hasta aproximadamente SIZE_MAX*SIZE_MAX .
Esta capacidad no se usa con frecuencia en muchas plataformas con direccionamiento lineal. Tales sistemas limitan calloc()con nmemb * size <= SIZE_MAX.
Considere un tipo de 512 bytes llamados disk_sectory el código quiere usar muchos sectores. Aquí, el código solo puede usar hasta SIZE_MAX/sizeof disk_sectorsectores.
size_t count = SIZE_MAX/sizeof disk_sector;
disk_sector *p = malloc(count * sizeof *p);
Considere lo siguiente que permite una asignación aún mayor.
size_t count = something_in_the_range(SIZE_MAX/sizeof disk_sector + 1, SIZE_MAX)
disk_sector *p = calloc(count, sizeof *p);
Ahora, si dicho sistema puede suministrar una asignación tan grande, es otro asunto. La mayoría de hoy no lo hará. Sin embargo, ha ocurrido durante muchos años cuando SIZE_MAXera 65535. Dada la ley de Moore , sospecho que esto ocurrirá alrededor de 2030 con ciertos modelos de SIZE_MAX == 4294967295memoria y grupos de memoria en el 100 de GBytes.
size_tmayor de 32 bits. La única pregunta es si se puede confiar en el uso calloccon valores cuyo producto excede SIZE_MAXpara producir cero en lugar de devolver un puntero a una asignación más pequeña.
calloc()asignaciones excedan SIZE_MAX. Ha sucedido en el pasado con 16 bits size_ty a medida que la memoria continúa abaratando, no veo ninguna razón para que no pueda suceder en el futuro, incluso si no es común .
SIZE_MAX. Ciertamente no requiere que haya ninguna circunstancia bajo la cual tal asignación pueda tener éxito; No estoy seguro de que haya algún beneficio particular al exigir que las implementaciones que no pueden manejar tales asignaciones deben regresar NULL(especialmente dado que es común que algunas implementaciones tengan mallocpunteros de retorno al espacio que aún no se ha comprometido y que podría no estar disponible cuando el código realmente intenta usar eso).
size_ta uint64_t?
Número de bloques:
malloc () asigna un solo bloque de memoria solicitada,
calloc () asigna múltiples bloques de la memoria solicitada
Inicialización:
malloc (): no borra e inicializa la memoria asignada.
calloc (): inicializa la memoria asignada por cero.
Velocidad:
malloc () es rápido.
calloc () es más lento que malloc ().
Argumentos y sintaxis:
malloc () toma 1 argumento:
bytes
calloc () toma 2 argumentos:
longitud
void *malloc(size_t bytes);
void *calloc(size_t length, size_t bytes);
Forma de asignación de memoria:
la función malloc asigna memoria del 'tamaño' deseado del montón disponible.
La función calloc asigna memoria que es el tamaño de lo que es igual a 'num * size'.
Significado en el nombre:
El nombre malloc significa "asignación de memoria".
El nombre calloc significa "asignación contigua".
malloc