-
Sempre que escrevemos um programa, é preciso reservar espaço para as informações que serão processadas. Para isso utilizamos as variáveis:
- Uma variável é uma posição de memória que armazena uma informação que pode ser modificada pelo programa. Ela deve ser definida antes de ser usada;
-
Infelizmente, nem sempre é possível saber, em tempo de execução, o quanto de memória um programa irá precisar;
-
Por Exemplo:
-
Imagine que você precise construir um programa que processe os valores dos salários dos funcionários de uma pequena empresa. PS.: Eu não sei o número de funcionários da empresa.
//Solução inicial
#include <stdio.h>
#include <stdlib.br>
int main (){
float salario [1000];
system ("pause");
return 0;
}
-
Posso ter dois inconvenientes:
- Ter mais de 1000 funcionários;
- Ter apenas 10 funcionários (990 posições de memória desperdiçadas);
-
Um programa em C suporta três tipos de alocação de memória:
- A alocação estática ocorre quando são declaradas variáveis globais ou estáticas; geralmente alocadas em Data.
- A alocação automática ocorre quando são declaradas variáveis locais e parâmetros de funções. O espaço para a alocação dessas variáveis é reservado quando a função é invocada, e liberado quando a função termina. Geralmente é usada a pilha (stack).
- A alocação dinâmica, quando o processo requisita explicitamente um bloco de memória para armazenar dados; o controle das áreas alocadas dinamicamente é manual ou semi-automático: o programador é responsável por liberar as áreas alocadas dinamicamente. A alocação dinâmica geralmente usa a área de heap.
-
Vamos considerar o seguinte:
- Arrays são agrupamentos sequenciais de dados de um mesmo tipo na memória;
- Um ponteiro guarda o endereço de um dado na memória;
- O nome do array é um ponteiro para o primeiro elemento do array;
-
Posso solicitar um bloco de memória e colocar a sua primeira posição em um ponteiro?
- A linguagem C permite alocar (reservar) dinamicamente (em tempos de execução) blocos de memória. Logo a alocação dinâmica permite ao programador “criar” arrays em tempo de execução, ou seja, alocar memória para novos arrays quando o programa está sendo executado, e não apenas quando se está escrevendo o programa;
- Assim quando não se sabe ao certo quanto de memória será necessário para armazenar os dados, pode-se definir o tamanho do array em tempo de execução, evitando assim o desperdício de memória;
-
De modo geral quando você inicializa um programa o sistema operacional mantém 4 “pedaços” distintos de memória para seu programa.

-
A alocação dinâmica de memória é um recurso importante em linguagens de programação que permite que você alocar e liberar memória durante a execução de um programa. Isso é útil quando você não conhece o tamanho exato de um objeto ou quando deseja controlar explicitamente a vida útil da memória.
-
A alocação dinâmica de memória é um mecanismo utilizado para possibilitar que uma quantidade de memória seja reservada durante o tempo de execução de uma aplicação. A região de memória utilizada para alocação dinâmica é conhecida como heap.
-
A linguagem C usa apenas 4 funções para o sistema de alocação dinâmica, disponíveis na stdlib.h:
- malloc -aloca o número especificado de bytes;
- calloc - aloca o número especificado de bytes e os inicializa para zero;
- realloc - aumenta ou diminui o tamanho do bloco de memória especificado, movendo-o se necessário;
- free - libera o bloco especificado de memória de volta para o sistema;
- Um operador (auxilia as demais funções na alocação de memória): Sizeof;
-
Malloc() - memory allocation
-
A função malloc() serve para alocar memória durante a execução do programa. É responsável pelo pedido de memória ao computador e retorna um ponteiro com o endereço do inicio do espaço de memória alocado;
- void *malloc (unsigned int num);
- void pois recebe um ponteiro genérico de memória;
- num: parâmetro que recebe o tamanho do espaço de memória em bytes a ser alocado;
- Caso der algum ERRO, retorna NULL;
-
Alocar 1000 bytes de memória livre:
char *p;
p = (char *) malloc(1000);
-
Alocar espaço para 50 inteiros:
int *p;
p = (int *) malloc(50 * sizeof( int ) );
-
Free()
- Diferente das variáveis definidas durante a escrita do programa, as variáveis alocadas dinamicamente não são liberadas automaticamente pelo programa;
Quando alocamos memória dinamicamente é necessário que nós a liberemos quando ela não for mais necessária;
Para isto existe a função free() cujo protótipo é:
- Assim, para liberar a memória, basta passar como parâmetro para a função free() o ponteiro que aponta para o início da memória a ser desalocada;
- Como o programa sabe quantos bytes devem ser liberados?
- Quando se aloca a memória, o programa guarda o número de bytes alocados numa "tabela de alocação" interna;
- Outro ponto muito importante é que a linguagem C não possui um gerenciamento automático do heap. Diante disso, é dever do programador liberar toda memória alocada na aplicação, evitando o que é chamado memory leak.
-
Calloc() - contiguous allocation
- A função calloc() também serve para alocar memória, mas possui um protótipo um pouco diferente:
- void *calloc (unsigned int num, unsigned int size);
- void pois recebe um ponteiro genérico de memória;
- num: quantidade de posições a serem alocadas;
- size: tamanho do tipo de dado alocado;
-
Realloc() - reallocate
- A função realloc é usada para redimensionar um espaço alocado previamente com malloc ou calloc;
- A função modifica o tamanho da memória previamente alocada e apontada por *ptr para aquele especificado por num;
- O valor de num pode ser maior ou menor que o original;
- void *realloc(void *prt, unsigned int num)
- 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 para o novo bloco, e nenhuma informação é perdida;
- Se *ptr for nulo, aloca num bytes e devolve um ponteiro (igual malloc);
- Se num é zero, a memória apontada por *ptr é liberada (igual free);
- Se não houver memória suficiente para a alocação, um ponteiro nulo é devolvido e o bloco original é deixado inalterado;
-
Verificação de Alocação: Sempre verifique se a alocação de memória foi bem-sucedida antes de usar um ponteiro alocado dinamicamente. Você pode verificar se o ponteiro é NULL após a alocação para garantir que a alocação ocorreu corretamente.
-
Gerenciamento de Memória: Ao usar alocação dinâmica de memória, lembre-se de que você é responsável por gerenciar a memória alocada. Certifique-se de liberar a memória quando não precisar mais dela para evitar vazamentos de memória.
-
A alocação dinâmica de memória é particularmente útil quando você precisa alocar memória para estruturas de dados cujo tamanho não é conhecido em tempo de compilação, como listas encadeadas, árvores e matrizes de tamanho variável. No entanto, o gerenciamento adequado da memória é essencial para evitar problemas como vazamentos de memória e corrupção de memória. Portanto, é importante entender e usar essas funções com cuidado.
-
Cabe ressaltar que em todas as funções de alocação dinâmica é necessário validar o endereço retornado, pois essas funções retornam NULL se a quantidade informada não pode ser alocada. Lembre-se, do primeiro artigo, que o valor NULL não impede erros de execução, porém fornece uma alternativa para testar se o ponteiro armazena um endereço válido. Em alguns compiladores é necessário realizar o cast do endereço retornado. No padrão ANSI não é necessário, ficando a critério do programador realizar o cast de forma explícita.
-
Independente do mecanismo utilizado num sistema de alocação dinâmica os ponteiros têm uma função especial. Por tratar-se de um mecanismo dinâmico, isto é, que varia conforme a execução do programa, os ponteiros oferecem os recursos necessários para manipular endereços de blocos de memória. Esse assunto torna-se importante para discutir um tópico conhecido como tipo de dados abstrato.
-
Exemplo