realloc - what is malloc in c




Diferença entre malloc e calloc? (8)

A documentação faz com que o calloc se pareça com malloc, que apenas faz a inicialização zero da memória; esta não é a principal diferença! A idéia do calloc é a de não usar a semântica de copy-on-write para alocação de memória. Quando você aloca memória com calloc, tudo mapeia 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 é alocada. Isto é freqüentemente usado para fazer tabelas hash ENORMES, por exemplo, já que as partes do hash que estão vazias não são suportadas por nenhuma memória extra (páginas); eles apontam alegremente para a única página inicializada como zero, que pode ser compartilhada até mesmo entre processos.

Qualquer gravação no endereço virtual é mapeada para uma página, se essa página for a página zero, outra página física é alocada, a página zero é copiada e o fluxo de controle é retornado para o processo do cliente. Isso funciona da mesma forma mapeada arquivos memória, memória virtual, etc trabalho .. 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/

Qual é a diferença entre fazer:

ptr = (char **) malloc (MAXELEMS * sizeof(char *));

ou:

ptr = (char **) calloc (MAXELEMS, sizeof(char*));

Quando é uma boa ideia usar calloc sobre malloc ou vice-versa?


A função calloc() que é declarada no cabeçalho <stdlib.h> oferece algumas vantagens sobre a função malloc() .

  1. Ele aloca memória como um número de elementos de um determinado tamanho e
  2. Inicializa a memória que é alocada para que todos os bits sejam zero.

Existem duas diferenças.
Primeiro, está no número de argumentos. malloc() recebe um único argumento (memória requerida 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 ponteiro NULL .

Sintaxe: ptr_var=(cast_type *)calloc(no_of_blocks , size_of_each_block); isto é, ptr_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 solicitada de memória, retornará um ponteiro nulo.

Sintaxe: ptr_var=(cast_type *)malloc(Size_in_bytes); A função malloc() recebe um argumento, que é o número de bytes a serem alocados, enquanto a função calloc() recebe dois argumentos, sendo um deles 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.


Não há diferença no tamanho do bloco de memória alocado. calloc apenas preenche o bloco de memória com o padrão físico de todos os bits zero. Na prática, é frequentemente assumido que os objetos localizados no bloco de memória alocados com calloc têm valor inicial como se fossem inicializados com 0 literal, isto é, inteiros devem ter valor 0 , variáveis ​​de ponto flutuante - valor de 0.0 , ponteiros - o valor apropriado valor de ponteiro nulo e assim por diante.

Do ponto de vista pedante, calloc (assim como memset(..., 0, ...) ) só é garantido para inicializar corretamente (com zeros) objetos do tipo unsigned char . Tudo o resto não é garantido para ser devidamente inicializado e pode conter a chamada representação de captura , o que causa um comportamento indefinido. Em outras palavras, para qualquer tipo diferente de unsigned char o patterm all-zero-bits mencionado acima pode representar um valor ilegal, a representação de trap.

Posteriormente, em um dos padrões da Technical Corrigenda to C99, o comportamento foi definido para todos os tipos inteiros (o que faz sentido). Ou seja, formalmente, na atual linguagem C, 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ê quiser usá-lo (considerando o acima) é com você. Eu pessoalmente prefiro evitá-lo completamente, usar malloc e executar minha própria inicialização.

Finalmente, outro detalhe importante é que o calloc é necessário para calcular o tamanho final do bloco internamente , multiplicando o tamanho do elemento pelo número de elementos. Enquanto faz isso, calloc deve observar possíveis transbordamentos aritméticos. Isso resultará em alocação malsucedida (ponteiro nulo) se o tamanho do bloco solicitado não puder ser calculado corretamente. Enquanto isso, sua versão malloc não faz nenhuma tentativa de assistir ao transbordamento. Ele alocará uma quantidade "imprevisível" de memória caso ocorra um estouro.


Uma diferença menos conhecida é que nos sistemas operacionais com alocação de memória otimista, como o Linux, o ponteiro retornado pelo malloc não é suportado pela memória real até que o programa realmente o toque.

calloc fato toca a memória (ela escreve zeros nela) e assim você terá certeza de que o sistema operacional está apoiando a alocação com a RAM real (ou swap). É também por isso que é mais lento que malloc (não só tem que zerar, o sistema operacional também deve encontrar uma área de memória adequada, possivelmente trocando outros processos)

Veja por exemplo esta questão SO para uma discussão mais aprofundada sobre o comportamento do malloc


Uma vantagem frequentemente negligenciada do calloc é que (implementações conformes de) ajudará a protegê-lo contra vulnerabilidades de estouro de 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 poderia resultar em uma pequena alocação e estouros de buffer subsequentes, se a count for maior que SIZE_MAX/sizeof *bar . O último falhará automaticamente nesse caso, já que um objeto grande não pode ser criado.

É claro que você pode ter que estar atento a implementações não conformes que simplesmente ignoram a possibilidade de estouro ... Se isso for uma preocupação nas plataformas que você segmenta, você terá que fazer um teste manual para estouro de qualquer maneira.


calloc() inicializa zero o buffer, enquanto malloc() deixa a memória não inicializada.

EDITAR:

Zerar a memória pode demorar um pouco, então você provavelmente desejará usar malloc() se esse desempenho for um problema. Se inicializar a memória for mais importante, use calloc() . Por exemplo, calloc() pode salvar uma chamada para memset() .


calloc é geralmente malloc+memset para 0

Geralmente, é um pouco melhor usar o 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 para o compilador em tempo de compilação eo compilador irá, na maioria dos casos, substituí-lo com as melhores instruções possíveis para a memória zero. Por outro lado, se memset estiver ocorrendo em calloc , o tamanho do parâmetro da alocação não é compilado no código calloc e o memset real é frequentemente chamado, o que normalmente conteria código para fazer o preenchimento byte-by-by até o limite longo, de ciclo para encher a memória em pedaços de sizeof(long) e, finalmente, preencher byte-byte do espaço restante. Mesmo que o alocador seja inteligente o suficiente para chamar alguns aligned_memset ele ainda será um loop genérico.

Uma exceção notável seria quando você está fazendo malloc / calloc de um pedaço muito grande de memória (alguns power_of_two kilobytes), em que a alocação de casos pode ser feita diretamente do kernel. Como os kernels do sistema operacional normalmente zeram toda a memória que eles distribuem por razões de segurança, o calloc inteligente o suficiente pode simplesmente retornar uma zeragem adicional. Novamente - se você está apenas alocando algo que você sabe que é pequeno, você pode estar melhor com o desempenho da malloc + memset.







calloc