www.samueldiasneto.com: Linguagem C - gerenciamento de memória

<<< Voltar Avançar >>>

15. Gerenciamento de memória

15.1 Preenchendo um intervalo de memória com uma constante byte

Para preencher um intervalo de memória utilize a função memset() . No gcc ela faz parte do arquivo de cabeçalho string.h e sua sintaxe é:

*memset(*STRING,CARACTER,BYTES)

a função acima preenche BYTES da área de memória apontada por *STRING com CARACTER . A função retorna um ponteiro para *STRING .

Ao preencher strings com esta função, pelo menos no ambiente Linux usando o gcc, a função não inseriu o caracter NULL para indicar o final da string, assim tive que fazer isso eu mesmo. Exemplo:

/* preechendo uma área de memória usando a função memset() */

#include <stdio.h>
#include <string.h>

int main()
  {
    char nome[10];

    memset(nome,'s',10);

    /* inserindo o valor NULL para indicar o final da string */
    nome[10] = 0; 

    printf("%s\n",nome);

    return(0);
  }

15.2 Copiando um intervalo de memória

Para copiar um intervalo de memória use a função memcpy() . Ela faz parte do arquivo de cabeçalho string.h e sua sintaxe é:

*memcpy(*DESTINO,*ORIGEM,BYTES)

a função acima copia BYTES da área de meória *ORIGEM para a área de memória *DESTINO . A função retorna um ponteiro para *DESTINO . Exemplo:

/* copiando um intervalo de memória */

#include <stdio.h>
#include <string.h>

int main()
  {
    float nrs1[5] = {1.1,1.2,1.3,1.4,1.5};
    float nrs2[5] = {5,5,5,5,5};
    int contador;

    printf("valores de nrs1\n");
    for(contador = 0;contador < 5;contador++)
      printf("%.1f ",nrs1[contador]);
    printf("\n");

    printf("valores de nrs2 inicialmente\n");
    for(contador = 0;contador < 5;contador++)
      printf("%.1f ",nrs2[contador]);
    printf("\n");

    memcpy(nrs2,nrs1,sizeof(nrs1));
    /* observe o uso do operador "sizeof" para
     * determinar o tamanho da área de memória
     * a ser copiada
     */

    printf("valores de nrs2 após a cópia\n");
    for(contador = 0;contador < 5;contador++)
      printf("%.1f ",nrs2[contador]);
    printf("\n");

    return(0);
  }

15.3 Movendo um intervalo de memória

Para mover uma área de memória use a função memmove() que está no arquivo de cabeçalho string.h . Sua sintaxe é:

*memmove(*DESTINO,*ORIGEM,BYTES)

a função acima move BYTES da área de memória *ORIGEM para a área de memória *DESTINO . A função retorna um ponteiro para *DESTINO . A diferença entre esta função e a função memcpy() mostrada na seção anterior é que com esta as área de memória *DESTINO e *ORIGEM podem se sobrepor. Exemplo:

/* movendo um intervalo de memória */

#include <stdio.h>
#include <string.h>

int main()
  {
    float nrs[5] = {1.1,1.2,1.3,1.4,1.5};
    float *ptr_nrs;
    int contador,bytes;

    printf("valores de nrs inicialmente\n");
    for(contador = 0;contador < 5;contador++)
      printf("%.1f ",nrs[contador]);
    printf("\n");

    ptr_nrs = nrs;
    ptr_nrs++;

    bytes = (sizeof(float) * 4);

    memmove(nrs,ptr_nrs,bytes);

    printf("valores de nrs após a movimentação\n");
    for(contador = 0;contador < 5;contador++)
      printf("%.1f ",nrs[contador]);
    printf("\n");

    return(0);
  }

15.4 Copiando até encontrar um byte específico

Usando a função memccpy() , que está no arquivo de cabeçalho string.h você pode copiar um intervalo de memória até encontrar um byte específico. A sintaxe da função é;

*memccpy(*DESTINO,*ORIGEM,CARACTER,BYTES)

Ela copia, no máximo, BYTES de *ORIGEM para *DESTINO , parando se CARACTER for encontrado. Ela retorna um ponteiro para o próximo byte após CARACTER em *DESTINO ou NULL se CARACTER não for encontrado nos primeiros BYTES de *ORIGEM . Exemplo:

/* copiando um intervalo de memória até encontrar um
 * byte específico */

#include <stdio.h>
#include <string.h>

int main()
  {
    char frase[80] = "E como dizia meu velho professor de física...estudem!!!";
    char copia[80];
    char *ptr_copia;

    /* "ptr_copia" aponta para o resultado de memccpy().
     * Se o caracter "." for encontrado em "frase",
     * será efetuada a cópia da área de memória até
     * este caracter e "ptr_copia" apontará para o
     * próximo byte após "." em "copia.
     * Caso contrário, serão copiados 80 bytes e
     * "ptr_copia" receberá o valor NULL.
     */
    ptr_copia = memccpy(copia,frase,'.',80);

    if(ptr_copia)
      *ptr_copia = 0;

    printf("%s\n",copia);

    return(0);
  }

15.5 Comparando duas áreas de memória

Você pode comparar duas áreas de memória usando a função memcmp() . Ela faz parte do arquivo de cabeçalho string.h e sua sintaxe é:

memcpy(*AREA1,*AREA2,BYTES)

Ela compara os primeiros BYTES de *AREA1 e *AREA2 .Se *AREA1 for maior ela retorna um inteiro maior que zero, se *AREA2 for maior ela retorna um inteiro menor que zero e caso as duas áreas sejam iguais ela retorna zero. Exemplo:

/* comparando duas áreas de memória */

#include <stdio.h>
#include <string.h>

int main()
  {
    char string1[7] = "aeiou";
    char string2[7] = "Aeiou";
    int resultado;

    printf("string1 = %s\n",string1);
    printf("string2 = %s\n\n",string2);

    resultado = memcmp(string1,string2,7);

    if(resultado > 0)
      printf("string1 é maior\n");
    else if(resultado < 0)
      printf("string2 é maior\n");
    else
      printf("string1 e string2 são iguais\n");

    return(0);
  }

  /* Faça algumas substituições no código
   * trocando o "A" maiúsculo de "string2"
   * para "string1" e/ou substituindo-o
   * por um "a" e observe os vários
   * resultados do programa.
   */

15.6 Trocando bytes adjacentes

Quando você precisar trocar os bytes adjacentes, normalmente para trocar dados entre máquinas que possuem ordenamento de bytes alto/baixo diferentes, use a função swab() . Ela faz parte do arquivo de cabeçalho string.h e sua sintaxe é:

swab(*ORIGEM,*DESTINO,BYTES)

Ela copia BYTES de *ORIGEM para *DESTINO trocando os bytes adjacentes, pares e ímpares. Exemplo:

/* trocando bytes adjacentes */

#include <stdio.h>
#include <string.h>

int main()
  {
    char str_origem[30] = "Trocando bytes adjacentes";
    char str_destino[30];

    memset(str_destino,'s',30);

    str_destino[30] = 0;

    printf("str_origem  => %s\n",str_origem);
    printf("str_destino => %s\n",str_destino);

    printf("chamando swab()\n");

    swab(str_origem,str_destino,30);

    printf("str_origem  => %s\n",str_origem);
    printf("str_destino => %s\n",str_destino);

    return(0);
  }

15.7 Alocando memória dinamicamente

Quando você declara uma matriz o compilador aloca memória para o armazenamento dos dados desta matriz. Caso você queira alterar o tamanho da matriz terá que modificar o código e recompilar o programa. Para evitar isso você pode alocar memória dinamicamente, ou seja, o programa aloca a memória necessária durante a execução. Para isso você pode usar as funções calloc() e malloc() . Em ambiente linux, usando o gcc, elas fazem parte do arquivo de cabeçalho stdlib.h .

A sintaxe de calloc() é:

*calloc(QUANTIDADE_DE_ELEMENTOS,TAMANHO)

Ela aloca memória para uma matriz com o número de elementos igual a QUANTIDADE_DE_ELEMENTOS , tendo cada um destes elementos TAMANHO bytes. Esta função retorna um ponteiro para o ínicio do bloco de memória alocado ou NULL caso ocorra algum problema.

Exemplo do uso de calloc() :

/* alocando memória dinamicamente com calloc() */

#include <stdio.h>
#include <stdlib.h>

int main()
  {
    int *matriz1;
    int nr_elementos_matriz1;
    int contador;

    printf("Alocando memória dinamicamente usando calloc()\n");

    printf("Entre com a quantidade de elementos
	da matriz de inteiros :");
    scanf("%d",&nr_elementos_matriz1);

    matriz1 = (int *) calloc(nr_elementos_matriz1,sizeof(int));
    /* Observe acima a instrução "(int *)". Isto é usado
     * para converter o ponteiro retornado por calloc()
     * para um ponteiro do tipo desejado. Caso você
     * estivesse alocando memória para um ponteiro de
     * ponto flutuante esta instrução seria "(float *").
     */

    if(matriz1)
      {
        for(contador = 0;contador < nr_elementos_matriz1;contador++)
          {
            printf("Entre com o %do elemento :",contador + 1);
            scanf("%d",&matriz1[contador]);

          }

        printf("\n");

        for(contador = 0;contador < nr_elementos_matriz1;contador++)
          printf("Exibindo o %do elemento : %d\n",
		  contador + 1,matriz1[contador]);
      }
    else
      printf("Erro ao alocar memória.\n");

    return(0);
  }

 

A sintaxe de malloc() é:

*malloc(BYTES)

Esta função aloca BYTES e retorna um ponteiro para o início da memória alocada ou NULL caso ocorra algum problema.

Exemplo do uso de malloc() :

/* alocando memória dinamicamente com malloc() */

#include <stdio.h>
#include <stdlib.h>

int main()
  {
    int *matriz1;
    int contador;
    int nr_elementos_matriz1;

    printf("Alocando memória dinamicamente usando malloc()\n");

    printf("Entre com a quantidade de elementos da matriz de inteiros :");
    scanf("%d",&nr_elementos_matriz1);

    matriz1 = (int *) malloc(nr_elementos_matriz1 * sizeof(int));
     /* Observe acima a instrução "(int *)". Isto é usado
     *  para converter o ponteiro retornado por malloc()
     *  para um ponteiro do tipo desejado. Caso você
     *  estivesse alocando memória para um ponteiro de
     *  ponto flutuante esta instrução seria "(float *").
     */

    if(matriz1)
      {
        for(contador = 0;contador < nr_elementos_matriz1;contador++)
          {
            printf("Entre com o %do elemento :",contador + 1);
            scanf("%d",&matriz1[contador]);

          }

        printf("\n");
        for(contador = 0;contador < nr_elementos_matriz1;contador++)
          printf("Exibindo o %do elemento : %d\n",
		  contador + 1,matriz1[contador]);
      }
    else
      printf("Erro ao alocar memória.\n");

    return(0);
  }

15.8 Liberando memória

Quando seu programa não precisar mais da memória alocada com as funções malloc() e calloc() ele deve liberar a memória. Para isso você pode usar a função free() , que pertence ao arquivo de cabeçalho stdlib.h e cuja sintaxe é:

free(*PONTEIRO)

Exemplo do uso de free() :

/* liberando memória anteriormente alocada */

#include <stdio.h>
#include <stdlib.h>

int main()
  {
    int *matriz1;
    int contador;
    int nr_elementos_matriz1;

    printf("Alocando memória dinamicamente usando malloc()\n");
    printf("e liberando a memória alocada com free()\n");

    printf("Entre com a quantidade de elementos da matriz de inteiros :");
    scanf("%d",&nr_elementos_matriz1);

    matriz1 = (int *) malloc(nr_elementos_matriz1 * sizeof(int));

    if(matriz1)
      {
        for(contador = 0;contador < nr_elementos_matriz1;contador++)
          {
            printf("Entre com o %do elemento :",contador + 1);
            scanf("%d",&matriz1[contador]);

          }
        printf("\n");

        for(contador = 0;contador < nr_elementos_matriz1;contador++)
          printf("Exibindo o %do elemento : %d\n",
		  contador + 1,matriz1[contador]);

        free(matriz1); /* liberando a memória alocada */
      }
    else
      printf("Erro ao alocar memória.\n");

    return(0);
  }

15.9 Alterando o tamanho da memória alocada

Para alterar o tamanho de um bloco de memória anteriormente alocado use a função realloc() . Ela faz parte do arquivo de cabeçalho stdlib.h e sua sintaxe é:

*realloc(*PONTEIRO,BYTES)

Ela altera o tamanho do bloco apontado por *PONTEIRO para BYTES . A memória recém-alocada não será inicializada. Se *PONTEIRO for NULL, a chamada será equivalente a malloc(BYTES) ; se BYTES for igual a zero, a chamada será equivalente a free(*PONTEIRO) . A menos que *PONTEIRO seja NULL, ele precisa ter sido retornado por uma chamada anterior para malloc() , calloc() ou realloc() .

Exemplo do uso de realloc() :

/* alterando um bloco de memória anteriormente alocado */

#include <stdio.h>
#include <stdlib.h>

int main()
  {
    char *frase;

    frase = (char *) malloc(10);

    if(frase)
      printf("10 bytes alocados com sucesso\n");
    else
      printf("Erro ao alocar memória\n");

    printf("\n");

    realloc(frase,1000);

    if(frase)
      printf("1000 bytes alocados com sucesso\n");
    else
      printf("Erro ao alocar memória\n");

    return(0);
  }

<<< Voltar Avançar >>>