# Programar em C/Gerenciamento de memória
## Alocação dinâmica

Todos os dados de um programa são armazenados na memória do computador; é muito comum necessitar reservar um certo espaço na memória para poder guardar dados mais tarde. Por exemplo, poderíamos reservar um espaço de 1000 bytes para guardar uma string que o usuário viesse a digitar, declarando um vetor de 1000 caracteres. E se quiséssemos reservar um espaço que só é conhecido no tempo de execução do programa? E se o espaço fosse muito grande, de modo que declarar vetores de tal tamanho seria inconveniente (pois, entre outras coisas, aumenta sem necessidade o tamanho do executável)?
Para solucionar esse problema, existe a alocação dinâmica de memória, que como o nome sugere, é uma maneira de alocar memória à medida que o programa vai sendo executado. As quatro funções relacionadas com a alocação dinâmica serão descritas a seguir.

### malloc e free

Essas duas funções são as mais básicas para o gerenciamento de memória. malloc é responsável pela alocação de um pedaço de memória, e free é responsável por liberar esse pedaço de memória.
A função malloc serve para alocar memória e tem o seguinte protótipo:
Para alocar um espaço na memória, precisamos fornecer à função malloc o número de bytes desejados. Ela aloca na memória e retorna um ponteiro void * para o primeiro byte alocado. O ponteiro void* pode ser atribuído a qualquer tipo de ponteiro. Se não houver memória suficiente para alocar a memória requisitada a função malloc retorna um ponteiro nulo.
Para saber o tamanho do bloco a alocar, precisaremos usar o operador sizeof. Ele permite também saber automaticamente o tamanho de structs criadas pelo usuário.
Veja um exemplo de alocação dinâmica:
Outros exemplos:
* O compilador aceita *p=*q porque são ambos int.
* O compilador aceita também p=q porque ambos são ponteiros e apontam para o mesmo tipo.
* Podemos simplificar p = malloc(sizeof(int)); por p = malloc(4); mas como temos sistemas operacionais de 16,32, 64 bits a primeira declaração torna as coisas mais portáveis.

### calloc

A função calloc também serve para alocar memória, mas possui um protótipo um pouco diferente:
A função calloc reserva um bloco com o tamanho (nelem x elsize) octetos consecutivos, isto é, aloca memória suficiente para um vetor de num objetos de tamanho size. Diferente de malloc, o bloco reservado é inicializado a 0. Essa função retorna um ponteiro void* para o primeiro byte alocado. O ponteiro void* pode ser atribuído a qualquer tipo de ponteiro. Se não houver memória suficiente para alocar a memória requisitada a função calloc retorna um ponteiro nulo.
Exemplo:
No exemplo acima, é alocada memória suficiente para se colocar n números inteiros. O operador sizeof retorna o número de bytes de um inteiro. Ele é útil para se saber o tamanho de tipos. O ponteiro void * que calloc retorna é convertido para um int* pelo cast e é atribuído a p. A declaração seguinte testa se a operação foi bem sucedida. Se não tiver sido, p terá um valor nulo, o que fará com que !p retorne verdadeiro. Se a operação tiver sido bem sucedida, podemos usar o vetor de inteiros alocados normalmente, por exemplo, indexando-o de p[0] a p[(a-1)].

### realloc

A função realloc serve para realocar memória e tem o seguinte protótipo:
A função realloc ajusta o tamanho de um bloco a size octetos consecutivos. A função modifica o tamanho da memória previamente alocada com malloc, calloc ou realloc e apontada por ptr para o tamanho especificado por size. O valor de size pode ser maior ou menor que o original. Um ponteiro para o bloco é devolvido porque realloc pode precisar mover o bloco para aumentar seu tamanho. Se isso ocorrer, o conteúdo do bloco antigo é copiado no novo bloco, o bloco antigo é liberado e nenhuma informação é perdida. Se não precisar mover, o valor retornado é igual a ptr. Se ptr for nulo, a função aloca size bytes e devolve um ponteiro, funcionando como malloc; se size é zero, a memória apontada por ptr é liberada. Se não houver memória suficiente para a alocação, um ponteiro nulo é devolvido e o bloco original é deixado inalterado.
Exemplo:

### Alocação Dinâmica de Vetores

A alocação dinâmica de vetores utiliza os conceitos aprendidos na aula sobre ponteiros e as funções de alocação dinâmica apresentados. Um exemplo de implementação para vetor real é fornecido a seguir:

### Alocação Dinâmica de Matrizes

A alocação dinâmica de memória para matrizes é realizada da mesma forma que para vetores, com a diferença que teremos um ponteiro apontando para outro ponteiro que aponta para o valor final, ou seja é um ponteiro para ponteiro, o que é denominado indireção múltipla. A indireção múltipla pode ser levada a qualquer dimensão desejada, mas raramente é necessário mais de um ponteiro para um ponteiro. Um exemplo de implementação para matriz real bidimensional é fornecido a seguir. A estrutura de dados utilizada neste exemplo é composta por um vetor de ponteiros (correspondendo ao primeiro índice da matriz), sendo que cada ponteiro aponta para o início de uma linha da matriz. Em cada linha existe um vetor alocado dinamicamente, como descrito anteriormente (compondo o segundo índice da matriz).