Manufaturação industrial
Internet das coisas industrial | Materiais industriais | Manutenção e reparo de equipamentos | Programação industrial |
home  MfgRobots >> Manufaturação industrial >  >> Industrial programming >> Linguagem C

Alocação Dinâmica de Memória em C: Dominando malloc, calloc, realloc e free

Antes de mergulhar na alocação dinâmica de memória em C, é essencial entender como a memória é gerenciada na linguagem.

Como o Gerenciamento de Memória Funciona em C

Quando você declara uma variável com tipo primitivo, o compilador aloca espaço para ela na stack automaticamente. Por exemplo, um float tipicamente ocupa 4 bytes (dependente da plataforma). Você pode confirmar isso com o operador sizeof:

#include <stdio.h>
int main() {
    float x;
    printf("O tamanho de float é %d bytes", sizeof(x));
    return 0;
}

A saída será:

O tamanho de float é 4 bytes

Um array de tamanho especificado também é alocado contiguamente na stack, com cada elemento ocupando o tamanho de seu tipo:

#include <stdio.h>
int main() {
    float arr[10];
    printf("O tamanho do array float com 10 elementos é %d", sizeof(arr));
    return 0;
}

O resultado é:

O tamanho do array float com 10 elementos é 40

Embora a alocação na stack seja automática, muitos programas requerem memória cujo tamanho não é conhecido até o tempo de execução. Essa necessidade é atendida pela alocação dinâmica de memória, que usa o heap em vez da stack.

Alocação Dinâmica de Memória em C

A alocação dinâmica envolve solicitar e liberar memória manualmente conforme necessário, com ponteiros rastreando os blocos alocados no heap. A biblioteca padrão C fornece várias funções para este propósito:

Vamos explorar cada função em detalhes.

Função malloc()

A função malloc() significa "memory allocation" (alocação de memória). Ela reserva um bloco de memória de tamanho especificado e retorna um ponteiro para ele. O ponteiro é tipicamente convertido para o tipo desejado:

ptr = (tipo_cast *) malloc(tamanho_em_bytes);

Exemplo:

#include <stdlib.h>
int main(){
    int *ptr;
    ptr = malloc(15 * sizeof(*ptr)); /* 15 inteiros */
    if (ptr != NULL) {
        *(ptr + 5) = 480; /* sexto elemento */
        printf("Valor do 6º inteiro é %d", *(ptr + 5));
    }
}

Saída:

Valor do 6º inteiro é 480

Pontos-chave:

  1. Use sizeof(*ptr) para tornar o código robusto contra mudanças de tipo.
  2. Verifique o valor de retorno NULL para detectar falha de alocação.
  3. Memória alocada é contígua; trate-a como array e use aritmética de ponteiros.

Alocação dinâmica não se limita a tipos primitivos; funciona com estruturas, arrays de caracteres e mais.

Função free()

Memória alocada com malloc(), calloc() ou realloc() deve ser liberada explicitamente para evitar vazamentos. A função free() realiza esta tarefa:

#include <stdio.h>
int main() {
    int* ptr = malloc(10 * sizeof(*ptr));
    if (ptr != NULL){
        *(ptr + 2) = 50;
        printf("Valor do 2º inteiro é %d", *(ptr + 2));
    }
    free(ptr);
}

Saída:

Valor do 2º inteiro é 50

Função calloc()

calloc() aloca múltiplos blocos de tamanho igual e inicializa cada byte com zero, tornando-o ideal para arrays e estruturas que requerem memória zerada:

ptr = (tipo_cast *) calloc(n, tamanho);

Exemplo – somando uma sequência aritmética:

#include <stdio.h>
int main() {
    int i, *ptr, sum = 0;
    ptr = calloc(10, sizeof(int));
    if (ptr == NULL) {
        printf("Erro! memória não alocada.");
        exit(0);
    }
    for (i = 0; i < 10; ++i) {
        *(ptr + i) = i;
        sum += *(ptr + i);
    }
    printf("Soma = %d", sum);
    free(ptr);
    return 0;
}

Resultado:

Soma = 45

calloc() vs. malloc()

Diferenças principais:

Função realloc()

A função realloc() altera o tamanho de uma alocação existente preservando seu conteúdo:

ptr = realloc(ptr, novo_tamanho);

Exemplo – estendendo um buffer de string:

#include <stdio.h>
#include <string.h>
int main () {
    char *ptr = malloc(10);
    strcpy(ptr, "Programming");
    ptr = realloc(ptr, 20); // aumenta
    strcat(ptr, " In 'C'");
    printf("%s, Endereço = %u", ptr, ptr);
    free(ptr);
    return 0;
}

Se a realocação falhar, realloc() retorna NULL e o bloco original permanece válido.

Arrays Dinâmicos

Arrays dinâmicos permitem que o número de elementos cresça durante a execução, um padrão comum em algoritmos e estruturas de dados:

#include <stdio.h>
#include <stdlib.h>
int main() {
    int *arr_dynamic = NULL;
    int elements = 2, i;
    arr_dynamic = calloc(elements, sizeof(int));
    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));
    printf("Após 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:

arr_dynamic[0]=0
arr_dynamic[1]=1
Após realloc
arr_dynamic[0]=0
arr_dynamic[1]=1
arr_dynamic[2]=2
arr_dynamic[3]=3

Resumo

Linguagem C

  1. Entendendo ROM, PROM, EPROM e EEPROM: Projeto, Programação e Identificação
  2. Fundamentos de C#: Essenciais de Entrada e Saída
  3. Dominando Declarações Using em C#: Imports, Aliases e Diretivas Estáticas
  4. Dominando Gerenciamento de Memória em C++: Uso Expert de new e delete
  5. Quatro Padrões Comprovados para Funções Definidas pelo Usuário em C
  6. Alocação Dinâmica de Memória em C: Dominando malloc, calloc, realloc e free
  7. Dominando Funções da Biblioteca Padrão C: Guia Prático
  8. Dominando Alocação Dinâmica de Arrays em C++: Guia Prático com Exemplos de Código
  9. Funções em C++ Explicadas com Exemplos Práticos de Código
  10. Dominando Funções em C: Estrutura, Declaração e Boas Práticas