Subsecções

32 Alocação dinâmica de memória

Quando você declara um array em um programa C , você deve informar quantos elementos devem ser reservados para este array. Se você conhece este número a priori, tudo está bem.

No entanto, o tamanho de um array pode ser desconhecido por uma série de fatores. Por exemplo, se você deseja ler todas as linhas de um arquivo e armazená-los em um array de seu programa, o tamanho de memória necessário dependerá do tamanho do arquivo. E se este tamanho variar muito de um arquivo para outro, você terá que reservar espaço suficiente para acomodar o maior tamanho de arquivo possível, o que é um desperdício se seu programa vai lidar com muitos arquivos de tamanho reduzido e apenas alguns arquivos com tamanho grande.

Definir um tamanho máximo para o suas estruturas de dados aumenta o tamanho de seu programa. Em um ambiente multitarefa como UNIXeste seu programa estará competingo por espaço livre de memória. Se seu programa aloca espaço desnecessariamente, isto quer dizer que menos processos poderão ocupar a memória para serem executados. Portanto, durante a gerência do processo de sua tarefa pelo sistema operacional, a trasnferência do programa do disco para a memória e vice-versa (processo conhecido como swapping), irá demorar mais.

Para permitir que o espaço para estruturas de dados de um programa possam ser alocados durante a execução do mesmo é que a linguagem C  define funções de biblioteca chamadas funções de alocação dinâmica de memória.

Estas funções são:

          #include <stdlib.h>

          void *malloc (int tamanho)
          void *calloc (int numero_elementos, int tamanho_elemento)
          void *realloc (void *area_alocada, int novo_tamanho)
          void free (void *area_alocada)

As funções malloc() e calloc() são usadas para alocar espaço para seus dados uma vez que você determinou quanto espaço você precisa. E se sua estimativa se revela muito grande ou muito pequena, você pode mudar o tamanho deste espaço alocado com a função realloc. Finalmente, uma vez que o programa terminou de usar o espaço alocado, a função free pode ser usada para liberar o espaço previamente alocado. Observe-se a diretiva #include que necessária para o uso das funções de alocação.

32.1 malloc e calloc

As funções malloc e calloc alocam espaço de memória. malloc recebe como argumento o número de bytes a ser alocado. calloc recebe como primeiro argumento o número de elementos a aser alocado. O segundo argumento indica o tamanho em bytes de cada elemento. calloc garante que o espaço alocado é inicializado com zeros, enquanto que malloc não.

Estas duas funções retornam um ponteiro para a nova área alocada. O tipo do ponteiro por convenção é char *. Caso o ponteiro seja usado para apontar para outro tipo qualquer, um cast no valor retornado deve ser usado. Observe o exemplo abaixo:

       #include <stdlib.h>

       char buf[30],
            *memchar;
       int *memint, i;

       ....

       memchar = malloc (sizeof(buf));  

       if (memchar == NULL) {
          printf ("Erro em alocacao de memoria\n");
          exit (1);
       }
       else {
           memcpy (memchar, buf, sizeof(buf));  /* copia o conteúdo de
                                                 * buf para memchar
                                                 */
       }

       memint = (int *) calloc (1, sizeof(int));  

       if (memint == NULL) {
          printf ("Erro em alocacao de inteiros\n");
          exit (1);
       }
       else {
             i = 0;
             do {
                 scanf("%d", memint + i);

                 if (memint[i]) {
                   memint = (int *) realloc (memint, (i + 2) * sizeof(int));

                   if (memint == NULL)
                      break;
                 }
             } while (memint[i++]);          
       }

Oberve no exemplo acima o uso de cast na chamada de calloc. Como o ponteiro retornado será usado para apontar para inteiros, o retorno da função deve ser convertido de acordo com o cast.

Quando não há sucesso na alocação de memória, as funções malloc e calloc retornam um ponteiro nulo, representado pela constante NULL. Assim, toda vez que um programa usa estas funções, deve-se testar o valor retornado para verificar se houve sucesso na alocação. É o que acontece no exemplo acima ao se testar os valores de memchar e memint imediatamente após a chamada das funções de alocação.

32.2 realloc

A função realloc é usada para redimensionar um espaço alocado previamente com malloc ou calloc. Seus argumentos são um ponteiro para o INÍCIO de uma área previamente alocada, e o novo tamanho, que pode ser maior ou menor que o tamanho original.

realloc retorna um ponteiro para a nova área alocada. Este ponteiro pode ser igual ao ponteiro original se o novo tamanho for menor que o tamanho original, e diferente do ponteiro original se o novo tamanho for maior que o tamanho original. Neste último caso, realloc copia os dados da área original para a nova área.

O último bloco else no exemplo da seção anterior é um exemplo de uso da função realloc. Neste bloco, usa-se a funçãorealloc para aumentar de 1 (um) o tamanho do array dinâmico representado por memint.

Armando Luiz Nicolini Delgado
2013-10-21