Alocação dinâmica de memória em C: malloc(), calloc()

⚡ Resumo Inteligente

A alocação dinâmica de memória em C reserva e libera memória do heap em tempo de execução usando as funções malloc(), calloc(), realloc() e free() da biblioteca stdlib.h, permitindo que os programas dimensionem arrays e estruturas de forma flexível quando os requisitos são desconhecidos antes da execução.

  • 🧠 Pilha vs. heap: As variáveis ​​básicas utilizam a pilha automática, enquanto a memória dinâmica reside no heap e é gerenciada manualmente por meio de ponteiros.
  • 📦 maloc(): Reserva um bloco não inicializado do tamanho de byte solicitado e retorna um ponteiro void ou NULL quando a memória for insuficiente.
  • 🔢 calloc (): Aloca múltiplos blocos para arrays, define cada byte como zero e retorna um ponteiro para o primeiro bloco.
  • 🔄 realloc(): Redimensiona um bloco existente para cima ou para baixo, preservando o conteúdo original em uma possível nova localização.
  • 🧹 gratuitamente(): Libera a memória para o heap; cada malloc() ou calloc() precisa de um free() correspondente para evitar vazamentos.
  • 🤖 Ajuda da IA: Assistentes de IA e o GitHub Copilot elaboram código de alocação e sinalizam chamadas free() ausentes e vazamentos.

Alocação dinâmica de memória em C

Como funciona o gerenciamento de memória em C?

Ao declarar uma variável usando um tipo de dado básico, o compilador C aloca automaticamente espaço de memória para a variável em um conjunto de memória chamado pilha.

Por exemplo, uma variável do tipo float normalmente ocupa 4 bytes (dependendo da plataforma) quando é declarada. Podemos verificar essa informação usando o operador sizeof, como mostrado no exemplo abaixo.

#include <stdio.h>
int main() { float x; printf("The size of float is %d bytes", sizeof(x)); return 0;}

A saída será:

 The size of float is 4 bytes

Além disso, um array com um tamanho especificado é alocado em blocos contíguos de memória, cada bloco tem o tamanho de um elemento:

#include <stdio.h>
int main() { float arr[10];
printf("The size of the float array with 10 element is %d", sizeof(arr)); return 0;}

O resultado é:

 The size of the float array with 10 element is 40

Como aprendemos até agora, ao declarar um tipo de dado básico ou um array, a memória é gerenciada automaticamente. No entanto, existe um processo para alocação de memória em C que permite implementar um programa no qual o tamanho do array permanece indefinido até a execução do programa (tempo de execução). Esse processo é chamado de "alocação dinâmica de memória".

Alocação dinâmica de memória em C

A alocação dinâmica de memória consiste na alocação e liberação manual de memória de acordo com as necessidades do seu programa. A memória dinâmica é gerenciada e servida por meio de ponteiros que apontam para o espaço de memória recém-alocado em uma área que chamamos de heap.

Agora você pode criar e destruir um array de elementos dinamicamente em tempo de execução sem problemas. Resumindo, o gerenciamento automático de memória usa a pilha e a alocação dinâmica de memória C usa o heap.

O biblioteca possui funções responsáveis ​​pelo gerenciamento dinâmico de memória.

função Propósito
malloc () Aloca a memória do tamanho solicitado e retorna o ponteiro para o primeiro byte do
espaço alocado.
calloc () Aloca o espaço para elementos de uma matriz. Inicializa os elementos para zero e retorna um ponteiro para a memória.
realloc () É usado para modificar o tamanho do espaço de memória alocado anteriormente.
Livre() Libera ou esvazia o espaço de memória alocado anteriormente.

Vamos discutir as funções acima com sua aplicação

função malloc() em C

A função C malloc() significa alocação de memória. É uma função usada para alocar um bloco de memória dinamicamente. Ele reserva espaço de memória de tamanho especificado e retorna o ponteiro nulo apontando para o local da memória. O ponteiro retornado geralmente é do tipo void. Isso significa que podemos atribuir a função C malloc() a qualquer ponteiro.

Sintaxe da função malloc():

ptr = (cast_type *) malloc (byte_size);

Aqui,

  • ptr é um ponteiro de cast_type.
  • A função C malloc() retorna um ponteiro para a memória alocada de byte_size.

Exemplo de malloc():

Example: ptr = (int *) malloc (50)

Quando esta instrução é executada com sucesso, um espaço de memória de 50 bytes é reservado. O endereço do primeiro byte do espaço reservado é atribuído ao ponteiro ptr do tipo int.

Considere outro exemplo:

#include <stdlib.h>
int main(){
int *ptr;
ptr = malloc(15 * sizeof(*ptr)); /* a block of 15 integers */
    if (ptr != NULL) {
      *(ptr + 5) = 480; /* assign 480 to sixth integer */
      printf("Value of the 6th integer is %d",*(ptr + 5));
    }
}

Saída:

Value of the 6th integer is 480

Função C malloc()

  1. Observe que sizeof(*ptr) foi usado em vez de sizeof(int) para tornar o código mais robusto quando a declaração *ptr for convertida para um tipo de dados diferente posteriormente.
  2. A alocação poderá falhar se a memória não for suficiente. Neste caso, ele retorna um ponteiro NULL. Portanto, você deve incluir código para verificar um ponteiro NULL.
  3. Tenha em mente que a memória alocada é contígua e pode ser tratada como um array. Podemos usar aritmética de ponteiro para acessar os elementos do array em vez de usar colchetes []. Aconselhamos usar + para se referir a elementos do array porque usar incrementação ++ ou += altera o endereço armazenado pelo apontador.

A função Malloc() também pode ser usada com o tipo de dados de caractere, bem como com tipos de dados complexos, como estruturas.

função free() em C

A memória para variáveis é automaticamente desalocado em tempo de compilação. Na alocação dinâmica de memória, você deve desalocar memória explicitamente. Caso contrário, você poderá encontrar um erro de falta de memória.

A função `free()` é chamada para liberar/desalocar memória em C. Ao liberar memória em seu programa, você disponibiliza mais memória para uso posterior.

Por exemplo:

#include <stdio.h>
int main() {
int* ptr = malloc(10 * sizeof(*ptr));
if (ptr != NULL){
  *(ptr + 2) = 50;
  printf("Value of the 2nd integer is %d",*(ptr + 2));
}
free(ptr);
}

Saída:

 Value of the 2nd integer is 50

Função calloc() em C

A função C calloc() significa alocação contígua. Esta função é usada para alocar vários blocos de memória. É uma função de alocação dinâmica de memória que é usada para alocar memória para estruturas de dados complexas, como arrays e estruturas.

A função Malloc() é usada para alocar um único bloco de espaço de memória, enquanto calloc() em C é usada para alocar vários blocos de espaço de memória. Cada bloco alocado pela função calloc() é do mesmo tamanho.

Sintaxe da função calloc():

ptr = (cast_type *) calloc (n, size);

A instrução acima é usada para alocar n blocos de memória do mesmo tamanho.

Depois que o espaço de memória é alocado, todos os bytes são inicializados em zero.

O ponteiro que está atualmente no primeiro byte do espaço de memória alocado é retornado.

Sempre que houver um erro na alocação de espaço de memória, como falta de memória, um ponteiro nulo será retornado.

Exemplo de calloc():

O programa abaixo calcula a soma de uma sequência aritmética.

#include <stdio.h>
    int main() {
        int i, * ptr, sum = 0;
        ptr = calloc(10, sizeof(int));
        if (ptr == NULL) {
            printf("Error! memory not allocated.");
            exit(0);
        }
        printf("Building and calculating the sequence sum of the first 10 terms \ n ");
        for (i = 0; i < 10; ++i) { * (ptr + i) = i;
            sum += * (ptr + i);
        }
        printf("Sum = %d", sum);
        free(ptr);
        return 0;
    }

Resultado:

Building and calculating the sequence sum of the first 10 terms
Sum = 45

calloc() vs. malloc(): principais diferenças

A seguir está a principal diferença entre malloc() versus calloc() em C:

A função calloc() é geralmente mais adequada e eficiente do que a função malloc(). Embora ambas as funções sejam usadas para alocar espaço de memória, calloc() pode alocar vários blocos ao mesmo tempo. Você não precisa solicitar um bloco de memória todas as vezes. A função calloc() é usada em estruturas de dados complexas que requerem maior espaço de memória.

O bloco de memória alocado por um calloc() em C é sempre inicializado em zero, enquanto na função malloc() em C, ele sempre contém um valor lixo.

função realloc() em C

Usando a função realloc() da linguagem C, você pode adicionar mais espaço à memória já alocada. Ela expande o bloco atual, mantendo o conteúdo original intacto. Em C, realloc() significa realocação de memória.

realloc() também pode ser usado para reduzir o tamanho da memória alocada anteriormente.

Sintaxe da função realloc():

ptr = realloc (ptr,newsize);

A instrução acima aloca um novo espaço de memória com um tamanho especificado na variável newsize. Após executar a função, o ponteiro retornará ao primeiro byte do bloco de memória. O novo tamanho pode ser maior ou menor que a memória anterior. Não podemos ter certeza de que o bloco recém-alocado apontará para o mesmo local do bloco de memória anterior. Esta função irá copiar todos os dados anteriores na nova região. Isso garante que os dados permanecerão seguros.

Exemplo de realloc():

#include <stdio.h>
int main () {
   char *ptr;
   ptr = (char *) malloc(10);
   strcpy(ptr, "Programming");
   printf(" %s,  Address = %u\n", ptr, ptr);

   ptr = (char *) realloc(ptr, 20); //ptr is reallocated with new size
   strcat(ptr, " In 'C'");
   printf(" %s,  Address = %u\n", ptr, ptr);
   free(ptr);
   return 0;
}

Sempre que realloc() em C resulta em uma operação malsucedida, ele retorna um ponteiro nulo e os dados anteriores também são liberados.

Matrizes Dinâmicas em C

Um array dinâmico em C permite que o número de elementos cresça conforme necessário. C A matriz dinâmica é amplamente utilizada em algoritmos de ciência da computação.

No programa a seguir, criamos e redimensionamos um array dinâmico em C

#include <stdio.h>
    int main() {
        int * arr_dynamic = NULL;
        int elements = 2, i;
        arr_dynamic = calloc(elements, sizeof(int)); //Array with 2 integer blocks
        for (i = 0; i < elements; i++) arr_dynamic[i] = i;
        for (i = 0; i < elements; i++) printf("arr_dynamic[%d]=%d\n", i, arr_dynamic[i]);
        elements = 4;
        arr_dynamic = realloc(arr_dynamic, elements * sizeof(int)); //reallocate 4 elements
        printf("After realloc\n");
        for (i = 2; i < elements; i++) arr_dynamic[i] = i;
        for (i = 0; i < elements; i++) printf("arr_dynamic[%d]=%d\n", i, arr_dynamic[i]);
        free(arr_dynamic);
    }

Resultado do programa C Dynamic array na tela:

 
arr_dynamic[0]=0
arr_dynamic[1]=1
After realloc
arr_dynamic[0]=0
arr_dynamic[1]=1
arr_dynamic[2]=2
arr_dynamic[3]=3

Perguntas Frequentes

Um vazamento de memória ocorre quando a memória alocada no heap por malloc() ou calloc() nunca é liberada. Evite isso associando cada alocação a uma chamada correspondente de free() assim que o bloco não for mais necessário.

Um ponteiro pendente ainda contém o endereço da memória que free() já liberou. Desreferenciá-lo causa comportamento indefinido, portanto, atribua NULL ao ponteiro imediatamente após liberar a memória para garantir a segurança.

Não. A linguagem C não possui coletor de lixo, portanto a memória alocada no heap nunca é liberada automaticamente. O programador deve liberar explicitamente cada bloco com a função `free()`; caso contrário, a alocação persiste até o término do programa.

Não. Chamar `free()` duas vezes no mesmo endereço resulta em uma liberação dupla e causa comportamento indefinido ou travamentos. Definir o ponteiro como `NULL` após a primeira chamada de `free()` torna qualquer chamada subsequente inofensiva.

realloc(NULL, size) funciona exatamente como malloc(size) e aloca um novo bloco. realloc(ptr, 0) libera o bloco, portanto, sempre capture o ponteiro retornado em vez de sobrescrever o original.

Ferramentas como Valgrind, AddressSanitizer e Dr. Memory. track cada alocação e relatar blocos que nunca foram liberados, juntamente com a linha exata, helping Você localiza vazamentos antes da liberação.

Sim. Um assistente de codificação com IA elabora sequências de malloc(), calloc() e free() a partir de um prompt, explica erros de ponteiro e sinaliza chamadas free() ausentes. Sempre compile e teste o código gerado antes de confiar nele.

Copiloto do GitHub Sugere-se a inclusão de blocos de alocação, verificações de NULL e chamadas free() correspondentes a partir de um comentário; revise cada conclusão para verificar vazamentos e tamanhos corretos antes de enviar o código.

Resuma esta postagem com: