usar - malloc sizeof
¿Diferencia entre malloc y calloc? (14)
¿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?
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 sintaxis de malloc (), 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 sintaxis de calloc (), 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:
Tanto malloc () como calloc () devolverán void * de forma predeterminada si no están fundidos por tipo.
Hay dos diferencias.
Primero, está en el número de argumentos. malloc()
toma un solo argumento (memoria requerida 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.calloc
llena la memoria con CERO y devuelve un puntero al primer byte. Si no encuentra el espacio suficiente, devuelve un punteroNULL
.
Sintaxis: ptr_var=(cast_type *)calloc(no_of_blocks , size_of_each_block);
es decir, ptr_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 función malloc()
toma un argumento, que es el número de bytes para asignar, mientras que la función calloc()
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 que malloc()
no lo hace.
La documentación hace que el calloc se vea como malloc, que simplemente no inicializa la memoria; ¡Esta no es la principal diferencia! La idea de calloc es abstraer la semántica de copia en escritura para la asignación de memoria. Cuando asigna memoria con calloc, todos los mapas se asignan 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 hacer tablas hash HUGE, por ejemplo, ya que las partes de hash que están vacías no están respaldadas por ninguna memoria adicional (páginas); apuntan felizmente a la página inicializada con un solo 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 en que funcionan los archivos asignados en la memoria, la memoria virtual, etc. .. usa 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/
La función calloc()
que se declara en el encabezado <stdlib.h>
ofrece <stdlib.h>
ventajas sobre la función malloc()
.
- Asigna memoria como un número de elementos de un tamaño dado, y
- Inicializa la memoria que se asigna para que todos los bits sean cero.
Las principales diferencias entre malloc y calloc son:
- malloc significa asignación de memoria mientras que calloc significa asignación contigua .
malloc toma solo un argumento , el tamaño del bloque, mientras que calloc toma dos argumentos , el número de bloques que se asignarán y el tamaño de cada bloque.
ptr = (tipo de reparto *) malloc (tamaño de byte) // malloc
ptr = (tipo de reparto *) calloc (no de bloques, tamaño de bloque); // calloc
malloc no realiza la inicialización de la memoria y todas las direcciones almacenan el valor de basura, mientras que el calloc realiza la inicialización de la memoria y las direcciones se inicializan a valores cero o nulos .
No hay diferencia en el tamaño del bloque de memoria asignado. calloc
simplemente llena el bloque de memoria con un patrón físico de todos los bits a cero. En la práctica, a menudo se asume que los objetos ubicados en el bloque de memoria asignado con calloc
tienen un valor inicial como si se hubieran inicializado con el literal 0
, es decir, los enteros deben tener un valor de 0
, variables de punto flotante - valor de 0.0
, punteros - los apropiados valor de puntero nulo, y así sucesivamente.
Sin embargo, desde el punto de vista pedante, calloc
(así como memset(..., 0, ...)
) solo garantiza la inicialización correcta (con ceros) de 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 causa un comportamiento indefinido. En otras palabras, para cualquier tipo que unsigned char
sea unsigned char
mencionado de todos los cero bits puede representar un valor ilegal, la representación de trampa.
Más adelante, en uno de los estándares de la Corrigenda Técnica a C99, el comportamiento se definió para todos los tipos de enteros (lo que tiene sentido). Es decir, formalmente, en el lenguaje C actual puede inicializar solo tipos de enteros con calloc
(y memset(..., 0, ...)
). Su uso para inicializar cualquier otra cosa en el caso general conduce a un comportamiento indefinido, desde el punto de vista del lenguaje C.
En la práctica, calloc
funciona, como todos sabemos :), pero depende de usted si desea usarlo (considerando lo anterior). Personalmente prefiero evitarlo por completo, usar malloc
lugar y realizar mi propia inicialización.
Finalmente, otro detalle importante es que se requiere calloc
para calcular el tamaño del bloque final internamente , multiplicando el tamaño del elemento por el número de elementos. Mientras hace eso, calloc
debe estar atento a posibles desbordamientos aritméticos. Resultará en una asignación fallida (puntero nulo) si el tamaño del bloque solicitado no se puede calcular correctamente. Mientras tanto, su versión malloc
no hace ningún intento de ver si hay desbordamiento. Asignará cierta cantidad "impredecible" de memoria en caso de que ocurra un desbordamiento.
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 SIZE_MAX*SIZE_MAX
.
Esta capacidad no se utiliza a menudo en muchas plataformas con direccionamiento lineal. Tales sistemas limitan el calloc()
con nmemb * size <= SIZE_MAX
.
Considere un tipo de 512 bytes llamado disk_sector
y el código quiere usar muchos sectores. Aquí, el código solo puede usar hasta SIZE_MAX/sizeof disk_sector
sectores.
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 bien, si un sistema de este tipo puede proporcionar 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_MAX
era 65535. Dada la ley de Moore , sospeche que esto ocurrirá alrededor de 2030 con ciertos modelos de memoria con SIZE_MAX == 4294967295
y pools de memoria en los 100 GB de GBytes.
Una diferencia menos conocida es que en los sistemas operativos con asignación de memoria optimista, como Linux, el puntero devuelto por malloc
no está respaldado por una memoria real hasta que el programa realmente lo toca.
calloc
sí toca la memoria (escribe ceros en ella) y, por lo tanto, se asegurará de que el sistema operativo esté respaldando la asignación con RAM (o swap) real. Esta es la razón por la que es más lento que malloc (no solo tiene que ponerlo a cero, sino que el sistema operativo también debe encontrar un área de memoria adecuada, posiblemente intercambiando otros procesos)
Vea, por ejemplo, esta pregunta de SO para una mayor discusión sobre el comportamiento de malloc
Una ventaja a menudo pasada por alto de calloc
es 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);
contra
size_t count = get_int32(file);
struct foo *bar = calloc(count, sizeof *bar);
Lo primero podría resultar en una pequeña asignación y subsiguientes desbordamientos del búfer, si el count
es mayor que la 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 esta es una preocupación en las plataformas a las que apunta, tendrá que hacer una prueba manual para el desbordamiento de todos modos.
de un artículo http://blogs.fau.de/hager/2007/05/08/benchmarking-fun-with-calloc-and-zero-pages/ en el blog de Georg Hager
Al asignar memoria usando calloc (), la cantidad de memoria solicitada no se asigna de inmediato. En su lugar, todas las páginas que pertenecen al bloque de memoria están conectadas a una sola página que contiene todos los ceros con algo de magia MMU (enlaces a continuación). Si esas páginas solo se leen (lo que es cierto para las matrices b, cyd en la versión original del índice de referencia), los datos se proporcionan desde la página de un solo cero, que, por supuesto, cabe en el caché. Tanto para los núcleos de bucle enlazados a la memoria. Si una página se escribe en (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 denomina copia en escritura, un enfoque de optimización bien conocido (que incluso he enseñado varias veces en mis clases de C ++). Después de eso, el truco de lectura cero ya no funciona para esa página y es por eso que el rendimiento fue mucho menor después de insertar el ciclo de inicio (supuestamente redundante).
calloc()
inicializa en cero el búfer, mientras que malloc()
deja la memoria sin inicializar.
EDITAR:
Poner a cero la memoria puede llevar un poco de tiempo, por lo que es probable que desee usar malloc()
si ese rendimiento es un problema. Si es más importante inicializar la memoria, use calloc()
. Por ejemplo, calloc()
puede ahorrarle una llamada a memset()
.
calloc
es generalmente malloc+memset
a 0
En general, es un poco mejor usar malloc+memset
explícitamente, especialmente cuando estás haciendo algo como:
ptr=malloc(sizeof(Item));
memset(ptr, 0, sizeof(Item));
Eso es mejor porque sizeof(Item)
es conocido para el compilador en el momento de la compilación y, en la mayoría de los casos, el compilador lo reemplazará con las mejores instrucciones posibles para memoria cero. Por otro lado, si memset
está ocurriendo en calloc
, el tamaño del parámetro de la asignación no se compila en el código de calloc
y se llama a menudo memset
real, que normalmente contendría código para hacer el relleno de byte por byte hasta el límite largo, sizeof(long)
ciclo para llenar la memoria en trozos de sizeof(long)
y, finalmente, rellene byte por byte del espacio restante. Incluso si el asignador es lo suficientemente inteligente como para llamar a algún aligned_memset
, seguirá siendo un bucle genérico.
Una excepción notable sería cuando está haciendo malloc / calloc de una gran cantidad de memoria (algunos power_of_two kilobytes) en cuyo caso la asignación se puede hacer directamente desde el kernel. Como los kernels del sistema operativo normalmente ponen a cero toda la memoria que regalan por razones de seguridad, el calloc lo suficientemente inteligente podría devolverlo con la puesta a cero adicional. Nuevamente, si solo está asignando algo que sabe que es pequeño, puede mejorar con malloc + memset en cuanto al rendimiento.
malloc()
y calloc()
son funciones de la biblioteca estándar de C que permiten la asignación de memoria dinámica, 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)
Hay principalmente dos diferencias entre los dos:
Comportamiento:
malloc()
asigna un bloque de memoria, sin inicializarlo, y leer el contenido de este bloque generará valores de basura.calloc()
, por otro lado, asigna un bloque de memoria y lo inicializa a ceros, y obviamente la lectura del contenido de este bloque resultará en ceros.Sintaxis:
malloc()
toma 1 argumento (el tamaño que se asignará), ycalloc()
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 sobre calloc()
ya que es más rápido. Si se desea una inicialización cero de los valores, use calloc()
lugar.
char *ptr = (char *) malloc (n * sizeof(char));
simplemente asigna n bytes
de memoria sin ninguna inicialización (es decir, esos bytes de memoria contendrán cualquier valor de basura).
char *ptr = (char *) malloc (n, sizeof(char));
Sin embargo, el método calloc()
en c realiza la inicialización como valor 0
para todos los bytes de memoria ocupados además de la función que realiza malloc()
.
Pero aparte de eso, hay una diferencia muy importante . Al llamar a malloc(x)
, asignará la memoria (es igual a x bloques) y devolverá el puntero al primer byte asignado. Sin embargo, no verificará si se asignan exactamente x bloques de memoria. Esto llevará al caso de desbordamiento de memoria. Sin embargo, calloc()
verifica el tamaño de la asignación. Si falla en la asignación de memoria o la verificación de los bytes asignados, simplemente devolverá nulo.