Qual é a diferença entre doing:
ptr = (char **) malloc (MAXELEMS * sizeof(char *));
ou:
ptr = (char **) calloc (MAXELEMS, sizeof(char*));
Quando é uma boa ideia usar calloc sobre malloc ou vice-versa?
ptr = calloc(MAXELEMS, sizeof(*ptr));
Qual é a diferença entre doing:
ptr = (char **) malloc (MAXELEMS * sizeof(char *));
ou:
ptr = (char **) calloc (MAXELEMS, sizeof(char*));
Quando é uma boa ideia usar calloc sobre malloc ou vice-versa?
ptr = calloc(MAXELEMS, sizeof(*ptr));
Respostas:
calloc()
fornece um buffer inicializado com zero, enquanto malloc()
deixa a memória não inicializada.
Para alocações grandes, a maioria das calloc
implementações nos sistemas operacionais convencionais obterá páginas zeradas conhecidas do sistema operacional (por exemplo, via POSIX mmap(MAP_ANONYMOUS)
ou Windows VirtualAlloc
), para que não seja necessário gravá-las no espaço do usuário. É assim que o normal também malloc
obtém mais páginas do sistema operacional; calloc
apenas aproveita a garantia do sistema operacional.
Isso significa que a calloc
memória ainda pode ser "limpa" e alocada preguiçosamente e a cópia na gravação mapeada para uma página física compartilhada de zeros em todo o sistema. (Supondo um sistema com memória virtual.)
Alguns compiladores podem otimizar malloc + memset (0) em calloc para você, mas você deve usar calloc explicitamente se quiser que a memória seja lida como 0
.
Se você nunca ler a memória antes de escrevê-la, use malloc
para que ela possa (potencialmente) fornecer memória suja de sua lista gratuita interna, em vez de obter novas páginas do sistema operacional. (Ou em vez de zerar um bloco de memória na lista livre para uma pequena alocação).
As implementações incorporadas calloc
podem deixar calloc
a memória com zero se não houver sistema operacional ou não for um sistema operacional multiusuário sofisticado que zere páginas para interromper o vazamento de informações entre os processos.
No Linux incorporado, o malloc poderia mmap(MAP_UNINITIALIZED|MAP_ANONYMOUS)
, que é ativado apenas para alguns kernels incorporados porque é inseguro em um sistema multiusuário.
calloc
não é necessariamente mais caro, pois o sistema operacional pode fazer alguns truques para acelerar isso. Eu sei que o FreeBSD, quando fica com o tempo ocioso da CPU, usa isso para executar um processo simples que gira e zera os blocos de memória desalocados e marca os blocos, portanto, processa com uma flag. Então, quando você o faz calloc
, ele primeiro tenta encontrar um desses blocos pré-zerados e apenas fornece a você - e provavelmente encontrará um.
Uma diferença menos conhecida é que, em sistemas operacionais com alocação de memória otimista, como o Linux, o ponteiro retornado malloc
não é suportado pela memória real até que o programa realmente o toque.
calloc
de fato toca a memória (escreve zeros nela) e, portanto, você terá certeza de que o sistema operacional está apoiando a alocação com RAM (ou swap) real. É também por isso que é mais lento que o malloc (não apenas precisa zerá-lo, o sistema operacional também deve encontrar uma área de memória adequada trocando outros processos)
Veja, por exemplo, esta questão do SO para uma discussão mais aprofundada sobre o comportamento do malloc.
calloc
não precisa escrever zeros. Se o bloco alocado consistir principalmente em novas zero páginas fornecidas pelo sistema operacional, poderá deixá-las intocadas. Obviamente, isso precisa calloc
ser ajustado ao sistema operacional, em vez de uma função genérica da biblioteca malloc
. Ou, um implementador pode calloc
comparar cada palavra com zero antes de zerá-lo. Isso não economizaria tempo, mas evitaria sujar as novas páginas.
dlmalloc
implementações semelhantes ignoram memset
se o pedaço foi obtido por meio de mmap
novas páginas anônimas (ou equivalente). Normalmente, esse tipo de alocação é usado para pedaços maiores, começando em 256k ou mais. Não conheço nenhuma implementação que faça a comparação contra zero antes de escrever zero além da minha.
omalloc
também pula o memset
; calloc
não precisa tocar em nenhuma página que ainda não esteja sendo usada pelo aplicativo (cache de página). Porém, implementações extremamente primitivascalloc
diferem.
Uma vantagem muitas vezes esquecida calloc
é que (implementações compatíveis) ajudarão a protegê-lo contra vulnerabilidades de estouro inteiro. 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);
O primeiro pode resultar em uma alocação minúscula e estouros de buffer subsequentes, se count
for maior que SIZE_MAX/sizeof *bar
. O último falhará automaticamente neste caso, pois um objeto que é grande não pode ser criado.
É claro que você pode estar atento a implementações não conformes que simplesmente ignoram a possibilidade de transbordamento ... Se essa é uma preocupação nas plataformas direcionadas, você terá que fazer um teste manual de transbordamento de qualquer maneira.
char
é um estouro, mas uma conversão definida pela implementação ao atribuir o resultado novamente a um objeto. char
size_t
64 bits, não há problema", é uma maneira de pensar falha que levará a erros de segurança. size_t
é um tipo abstrato que representa tamanhos e não há razão para pensar que o produto arbitrário de um número de 32 bits e um size_t
(nota: sizeof *bar
em princípio, poderia ser maior que 2 ^ 32 em uma implementação C de 64 bits!) se encaixam size_t
.
A documentação faz com que o calloc pareça malloc, que apenas inicializa zero a memória; essa não é a principal diferença! A idéia do calloc é abstact semântica copy-on-write para alocação de memória. Quando você aloca memória com calloc, tudo é mapeado para a mesma página física que é inicializada como zero. Quando qualquer uma das páginas da memória alocada é gravada em uma página física, ela é alocada. Isso geralmente é usado para criar tabelas de hash ENORMES, por exemplo, porque as partes vazias de hash não são suportadas por nenhuma memória extra (páginas); eles apontam para a única página inicializada com zero, que pode ser compartilhada entre processos.
Qualquer gravação no endereço virtual é mapeada para uma página, se essa página é a página zero, outra página física é alocada, a página zero é copiada para lá e o fluxo de controle é retornado ao processo do cliente. Isso funciona da mesma maneira que os arquivos mapeados na memória, memória virtual, etc. funcionam .. ele usa paginação.
Aqui está uma história de otimização sobre o tópico: http://blogs.fau.de/hager/2007/05/08/benchmarking-fun-with-calloc-and-zero-pages/
Não há diferença no tamanho do bloco de memória alocado. calloc
apenas preenche o bloco de memória com um padrão físico de zero-bits. Na prática, assume-se frequentemente que os objetos localizados no bloco de memória alocado com calloc
valor inicial como se tivessem sido inicializados com literal 0
, ou seja, números inteiros devem ter valor de 0
variáveis de ponto flutuante - valor de 0.0
, ponteiros - o valor de ponteiro nulo apropriado , e assim por diante.
Do ponto de vista pedante, porém, calloc
(e também memset(..., 0, ...)
) é garantido que apenas inicialize adequadamente (com zeros) objetos do tipo unsigned char
. Não há garantia de que tudo o mais seja inicializado corretamente e pode conter a chamada representação de interceptação , o que causa comportamento indefinido. Em outras palavras, para qualquer outro tipo que não unsigned char
o padrão de todos os bits zero acima mencionado pode representar um valor ilegal, representação de interceptação.
Posteriormente, em uma das correções técnicas para o padrão C99, o comportamento foi definido para todos os tipos de números inteiros (o que faz sentido). Ou seja, formalmente, no idioma C atual, você pode inicializar apenas tipos inteiros com calloc
(e memset(..., 0, ...)
). Usá-lo para inicializar qualquer outra coisa, em geral, leva a um comportamento indefinido, do ponto de vista da linguagem C.
Na prática, calloc
funciona, como todos sabemos :), mas se você deseja usá-lo (considerando o exposto acima) é com você. Pessoalmente, prefiro evitá-lo completamente, usar malloc
e executar minha própria inicialização.
Finalmente, outro detalhe importante calloc
é o necessário para calcular internamente o tamanho final do bloco , multiplicando o tamanho do elemento pelo número de elementos. Ao fazer isso, calloc
deve observar o possível estouro aritmético. Isso resultará em alocação malsucedida (ponteiro nulo) se o tamanho do bloco solicitado não puder ser calculado corretamente. Enquanto isso, sua malloc
versão não faz nenhuma tentativa de observar o estouro. Ele alocará uma quantidade "imprevisível" de memória, caso ocorra um estouro.
memset(p, v, n * sizeof type);
um problema porque n * sizeof type
pode transbordar. Acho que vou precisar usar um for(i=0;i<n;i++) p[i]=v;
loop para código robusto.
n
elementos em que um elemento tenha o tamanho sizeof type
, ele n*sizeof type
não poderá exceder, porque o tamanho máximo de qualquer objeto deve ser menor que SIZE_MAX
.
SIZE_MAX
, ainda não há matrizes aqui. O ponteiro retornado de calloc()
pode apontar para a memória alocada que excede SIZE_MAX
. Muitas implementações limitam o produto dos 2 argumentos calloc()
a SIZE_MAX
, mas a especificação C não impõe esse limite.
de um artigo Benchmarking divertido com calloc () e zero páginas no Blog de Georg Hager
Ao alocar memória usando calloc (), a quantidade de memória solicitada não é alocada imediatamente. Em vez disso, todas as páginas que pertencem ao bloco de memória são conectadas a uma única página contendo todos os zeros por alguma mágica da MMU (links abaixo). Se essas páginas forem lidas apenas (o que era verdadeiro para as matrizes b, c e d na versão original do benchmark), os dados são fornecidos a partir da única página zero, que, é claro, se encaixa no cache. Tanta coisa para os kernels de loop vinculados à memória. Se uma página é gravada (não importa como), ocorre uma falha, a página "real" é mapeada e a página zero é copiada para a memória. Isso é chamado de copiar na gravação, uma abordagem de otimização conhecida (que eu já ensinei várias vezes em minhas palestras em C ++). Depois disso,
calloc
é geralmente malloc+memset
0
Geralmente é um pouco melhor usar malloc+memset
explicitamente, especialmente quando você está fazendo algo como:
ptr=malloc(sizeof(Item));
memset(ptr, 0, sizeof(Item));
Isso é melhor porque sizeof(Item)
é conhecido pelo compilador no momento da compilação e, na maioria dos casos, o substitui pelas melhores instruções possíveis para zerar a memória. Por outro lado, se memset
estiver ocorrendo calloc
, o tamanho do parâmetro da alocação não é compilado no calloc
código e o real memset
é frequentemente chamado, o que normalmente contém código para preencher byte a byte até o limite longo, em vez de alternar para o preenchimento. memória em sizeof(long)
pedaços e, finalmente, preenchimento de byte a byte do espaço restante. Mesmo que o alocador seja inteligente o suficiente para chamar alguns aligned_memset
, ainda será um loop genérico.
Uma exceção notável seria quando você estiver fazendo malloc / calloc de uma grande parte da memória (alguns power_of_two kilobytes), caso em que a alocação pode ser feita diretamente do kernel. Como os kernels do SO normalmente zeram toda a memória que liberam por motivos de segurança, um calloc inteligente o suficiente pode devolvê-lo sem zerar adicional. Novamente - se você está apenas alocando algo que sabe ser pequeno, pode ser melhor usar o malloc + memset em termos de desempenho.
calloc()
mais lento que malloc()
: a multiplicação para o tamanho. calloc()
é necessário usar uma multiplicação genérica (se size_t
for 64 bits, mesmo a operação muito cara de 64 bits * 64 bits = 64 bits) enquanto o malloc () geralmente terá uma constante de tempo de compilação.
struct foo { char a,b,c; };
. calloc
é sempre melhor que malloc
+ memset
, se você sempre limpar toda a malloc
região ed. calloc
também tem uma verificação cuidadosa, mas eficiente, do excesso de int nos elementos size *.
Diferença 1:
malloc()
geralmente aloca o bloco de memória e é o segmento de memória inicializado.
calloc()
aloca o bloco de memória e inicializa todo o bloco de memória em 0.
Diferença 2:
Se você considerar a malloc()
sintaxe, serão necessários apenas 1 argumento. Considere o seguinte exemplo abaixo:
data_type ptr = (cast_type *)malloc( sizeof(data_type)*no_of_blocks );
Ex: se você deseja alocar 10 blocos de memória para o tipo int,
int *ptr = (int *) malloc(sizeof(int) * 10 );
Se você considerar a calloc()
sintaxe, serão necessários 2 argumentos. Considere o seguinte exemplo abaixo:
data_type ptr = (cast_type *)calloc(no_of_blocks, (sizeof(data_type)));
Ex: se você deseja alocar 10 blocos de memória para o tipo int e inicializar tudo isso em ZERO,
int *ptr = (int *) calloc(10, (sizeof(int)));
Semelhança:
Ambos malloc()
e calloc()
retornarão nulo * por padrão, se não forem do tipo fundido.!
Existem duas diferenças.
Primeiro, está no número de argumentos. malloc()
usa um único argumento (memória necessária em bytes), enquanto calloc()
precisa de dois argumentos.
Em segundo lugar, malloc()
não inicializa a memória alocada, enquanto calloc()
inicializa a memória alocada para ZERO.
calloc()
aloca uma área de memória, o comprimento será o produto de seus parâmetros. calloc
preenche a memória com ZERO e retorna um ponteiro para o primeiro byte. Se não conseguir localizar espaço suficiente, ele retornará um NULL
ponteiro.Sintaxe: ptr_var=(cast_type *)calloc(no_of_blocks , size_of_each_block);
ieptr_var=(type *)calloc(n,s);
malloc()
aloca um único bloco de memória de REQUSTED SIZE e retorna um ponteiro para o primeiro byte. Se não conseguir localizar a quantidade necessária de memória, ele retornará um ponteiro nulo.Sintaxe: ptr_var=(cast_type *)malloc(Size_in_bytes);
A malloc()
função aceita um argumento, que é o número de bytes a serem alocados, enquanto a calloc()
função recebe dois argumentos, um sendo o número de elementos e o outro o número de bytes a serem alocados para cada um desses elementos. Além disso, calloc()
inicializa o espaço alocado para zeros, enquanto malloc()
não.
A calloc()
função declarada no <stdlib.h>
cabeçalho oferece algumas vantagens sobre a malloc()
função.
malloc()
e calloc()
são funções da biblioteca padrão C que permitem alocação dinâmica de memória, o que significa que ambas permitem alocação de memória durante o tempo de execução.
Seus protótipos são os seguintes:
void *malloc( size_t n);
void *calloc( size_t n, size_t t)
Existem principalmente duas diferenças entre os dois:
Comportamento: malloc()
aloca um bloco de memória, sem inicializá-lo, e a leitura do conteúdo desse bloco resultará em valores de lixo. calloc()
, por outro lado, aloca um bloco de memória e o inicializa em zeros, e obviamente a leitura do conteúdo desse bloco resultará em zeros.
Sintaxe: malloc()
recebe 1 argumento (o tamanho a ser alocado) e calloc()
recebe dois argumentos (número de blocos a serem alocados e tamanho de cada bloco).
O valor de retorno de ambos é um ponteiro para o bloco de memória alocado, se for bem-sucedido. Caso contrário, NULL será retornado, indicando a falha na alocação de memória.
Exemplo:
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));
A mesma funcionalidade que calloc()
pode ser obtida usando malloc()
e 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));
Observe que, de malloc()
preferência, é usado mais, calloc()
pois é mais rápido. Se desejar inicializar com zero os valores, use calloc()
.
Uma diferença ainda não mencionada: limite de tamanho
void *malloc(size_t size)
só pode alocar até SIZE_MAX
.
void *calloc(size_t nmemb, size_t size);
pode alocar-se sobre SIZE_MAX*SIZE_MAX
.
Essa capacidade não é frequentemente usada em muitas plataformas com endereçamento linear. Tais sistemas limitam calloc()
com nmemb * size <= SIZE_MAX
.
Considere um tipo de 512 bytes chamado disk_sector
e o código deseja usar vários setores. Aqui, o código pode usar apenas SIZE_MAX/sizeof disk_sector
setores.
size_t count = SIZE_MAX/sizeof disk_sector;
disk_sector *p = malloc(count * sizeof *p);
Considere o seguinte, que permite uma alocação ainda maior.
size_t count = something_in_the_range(SIZE_MAX/sizeof disk_sector + 1, SIZE_MAX)
disk_sector *p = calloc(count, sizeof *p);
Agora, se esse sistema pode fornecer uma alocação tão grande é outra questão. Hoje a maioria não vai. No entanto, ocorre há muitos anos quando SIZE_MAX
foi 65535. Dada a lei de Moore , suspeite que isso ocorra por volta de 2030 com certos modelos de memória com SIZE_MAX == 4294967295
e conjuntos de memória nos 100 GBytes.
size_t
aumentará em 32 bits. A única questão é se o uso de calloc
valores cujo produto excede o valor SIZE_MAX
zero, em vez de retornar um ponteiro para uma alocação menor.
calloc()
alocações superiores SIZE_MAX
. Isso aconteceu no passado com 16 bits size_t
e, como a memória continua barateando, não vejo razão para que isso não aconteça no futuro, mesmo que não seja comum .
SIZE_MAX
. Certamente não exige que haja qualquer circunstância sob a qual tal alocação possa ter sucesso; Não tenho certeza de que exista algum benefício específico ao exigir que as implementações que não podem lidar com essas alocações devam retornar NULL
(especialmente porque é comum que algumas implementações tenham malloc
ponteiros de retorno para o espaço que ainda não foi confirmado e que pode não estar disponível quando o código realmente tentar usar isto).
size_t
a uint64_t
?
Número de blocos:
malloc () atribui um único bloco de memória solicitada,
calloc () atribui vários blocos da memória solicitada
Inicialização:
malloc () - não limpa e inicializa a memória alocada.
calloc () - inicializa a memória alocada por zero.
Velocidade:
malloc () é rápido.
calloc () é mais lento que malloc ().
Argumentos e sintaxe:
malloc () leva 1 argumento:
bytes
calloc () recebe 2 argumentos:
comprimento
void *malloc(size_t bytes);
void *calloc(size_t length, size_t bytes);
Alocação de maneira de memória:
A função malloc atribui memória do 'tamanho' desejado a partir da pilha disponível.
A função calloc atribui à memória o tamanho igual ao 'num * size'.
Significado no nome:
O nome malloc significa "alocação de memória".
O nome calloc significa "alocação contígua".
malloc