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