Gerenciamento de Memória

Até agora não vimos gerenciamento manual de memória, apenas automático. Todas variáveis auto que criamos são destruídas automaticamente quando saem do escopo onde foram declaradas. A duração estática de armazenamento evita essa destruição, porém o objeto estático é compartilhado entre todas chamadas da função e persiste durante toda a execução programa. Para ter controle total da duração de um objeto na memória, é necessário utilizar as funções de gerenciamento de memória malloc e free, de <stdlib.h>.

Função malloc

A função malloc recebe a quantidade de bytes a serem alocados e retorna um ponteiro que se refere à memória alocada. Isso significa que para alocar e utilizar um int, basta fazer int *p = malloc(sizeof *p); ou int *p = malloc(sizeof(int));. Todas as indireções no ponteiro acessarão o objeto alocado.

int *AlocarInt(void)
{
    return malloc(sizeof(int));
}

int main(void)
{
    int *a = AlocarInt(),
        *b = AlocarInt(),
        *c = AlocarInt();

    *a = 1;
    *b = 2;
    *c = 3;

    // Exibe "1, 2, 3"
    printf("%d, %d, %d\n",
           *a, *b, *c);

    return 0;
}

Funções em C não podem retornar arrays mas podem retornar ponteiros. Assim, uma forma de simular o retorno de array é alocar um array com malloc e retornar um ponteiro para ele. Como exemplo, vejamos uma função abaixo.

// Retorna um array de qtd ints com valor val
int *FabricarArray(size_t qtd, int val)
{
    int *array = malloc(sizeof(int[qtd]));

    for (size_t i = 0; i < qtd; i = i + 1)
        array[i] = val;

    return array;
}

int main(void)
{
    int *array = FabricarArray(9, 5);

    // Exibirá "5 5 5 5 5 5 5 5 5 "
    for (size_t i = 0; i < 9; i = i + 1)
        printf("%d ", array[i]);

    return 0;
}

Lembre-se que embora um ponteiro suporte o operador [] e simule um array, ele não é exatamente um array. O operador sizeof na variável array do código acima não resulta no tamanho do array retornado pela função e sim no tamanho do ponteiro.

int array[100];
int *ponteiro = FabricarArray(100, 0);

printf("sizeof array: %zu\nsizeof ponteiro: %zu\n",
        sizeof array, sizeof ponteiro);

Em um sistema específico, a execução do código acima exibiu sizeof array: 400 e sizeof ponteiro: 8, embora ambos possam acessar 100 ints com o operador [].

Função free

Toda a memória alocada por malloc continua alocada até ser manualmente liberada. Isso é feito aplicando a função free ao ponteiro que foi retornado por malloc. O ponteiro retornado pela nossa função FabricarArray é alocado por malloc, portanto esse procedimento deve ser feito.

int main(void)
{
    int *array = FabricarArray(9, 5);

    /* Utilizar o array ... */

    free(array);

    return 0;
}

Após o free, acessar o ponteiro com * resulta em comportamento indefinido até que um novo alvo válido seja dado a ele.

Referências

  • ISO/IEC JTC1/SC22/WG14 N2310:
    • 7.22.3.3 The free function