Mudanças entre as edições de "AULA 19 - Programação 1 - Graduação"

De MediaWiki do Campus São José
Ir para: navegação, pesquisa
(Criou página com '=Alocação Dinâmica de Memória= ==Objetivos== *Anatomia de um programa em execução; *Alocação dinâmica de memória. ==A área de heap e o layout de memória de um prog...')
 
(A área de heap e o layout de memória de um programa C)
 
(21 revisões intermediárias pelo mesmo usuário não estão sendo mostradas)
Linha 6: Linha 6:
 
*Alocação dinâmica de memória.
 
*Alocação dinâmica de memória.
  
==A área de heap e o layout de memória de um programa C==
+
==A área de ''heap'' e o ''layout'' de memória de um programa C==
  
 
Neste link podemos ter uma ideia da anatomia de um programa na memória do computador.
 
Neste link podemos ter uma ideia da anatomia de um programa na memória do computador.
Linha 37: Linha 37:
 
*[http://www.cplusplus.com/reference/cstdlib/free/?kw=free free]: libera memória;
 
*[http://www.cplusplus.com/reference/cstdlib/free/?kw=free free]: libera memória;
 
*[http://www.cplusplus.com/reference/cstdlib/realloc/ realloc]: realoca memória
 
*[http://www.cplusplus.com/reference/cstdlib/realloc/ realloc]: realoca memória
*[http://pt.wikipedia.org/wiki/Calloc calloc]:
+
*[http://pt.wikipedia.org/wiki/Calloc calloc]: aloca n bytes de memória e zera.
  
 
http://www.linuxjournal.com/article/4681
 
http://www.linuxjournal.com/article/4681
 
http://www.cs.cmu.edu/~guna/15-123S11/Lectures/Lecture08.pdf
 
http://www.cs.cmu.edu/~guna/15-123S11/Lectures/Lecture08.pdf
  
Exemplo 1: Alocação dinâmica de números inteiros (exercício puramente didático):
+
;EXEMPLO 1: Alocação dinâmica de números inteiros (exercício puramente didático):
  
 
<syntaxhighlight lang=c>
 
<syntaxhighlight lang=c>
Linha 64: Linha 64:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
===Alocando uma estrutura ===
+
;EXEMPLO 2: Diferente da função '''malloc''', '''calloc''' além de inicializar os espaços de memória ainda atribui o valor 0 (zero) para cada um deles.
 +
 
 +
<syntaxhighlight lang=c>
 +
#include <stdio.h>
 +
#include <stdlib.h>
 +
 +
int main(void){
 +
 +
    int *valores, *aux;
 +
    int qtd, i, vlr;
 +
 +
    printf("\nEntre com a quantidade de números: ");
 +
    scanf("%d", &qtd);
 +
 +
    if(qtd == 0)
 +
        exit(0);
 +
 
 +
//Aloca um vetor com a quantidade recebida em qtd
 +
    valores = (int *) calloc(qtd, sizeof (int));
 +
 
 +
//Imprime o endereco e valor (zero) para a quantidade de números informada
 +
    aux = valores;
 +
    for(i = 1; i <= qtd; i++){
 +
        printf("%p\t%d\n", aux, *aux);
 +
        aux++;
 +
    }
 +
 +
    aux = valores; //Ponteiro para o primeiro espaço de memória
 +
    for(i = 1; i <= qtd; i++){
 +
        printf("Digite o número %d ->: ", i);
 +
        scanf("%d", &vlr);
 +
        *aux = vlr;
 +
        aux++;
 +
    }
 +
 +
    aux = valores; //Retorna à posição inicial no mapa de memória
 +
    for(i = 1; i <= qtd; i++){
 +
        printf("%p\t%d\n", aux, *aux);
 +
        aux++;
 +
    }
 +
 +
    free(valores);
 +
 +
    return 0;
 +
}
 +
</syntaxhighlight>
 +
 
 +
 
 +
 
 +
;EXEMPLO 3: Vejamos comos diferentes elementos do programa são armazenados quando esse programa é executado. Os comentários no código explicam onde as variáveis ficam armazenadas.
 +
 
 +
<syntaxhighlight lang=c>
 +
int bss1;
 +
static double bss2;
 +
char *bss3;
 +
// estas variáveis são armazenadas no segmento de dados não inicializado (BSS)
 +
int init1=0;
 +
float init2=10.0;
 +
char *init3="Alo mundo!";
 +
// estas variáveis são armazenadas no segmento de dados inicializados (DATA)
 +
// o código para função principal é armazenado em (code segment)
 +
int main()
 +
{
 +
int local1=10; // esta variável é armazenada na pilha (stack) e código de inicialização é gerado pelo compilador.
 +
int local2; //esta variável não é inicializada, portanto, tem valor de lixo. Ela não fica inicializada com zero.
 +
static int local3; // esta é alocada no segmento BSS e é inicializada com zero.
 +
static int local4=100; //este é alocada e inicializada no segmento de dados
 +
int *local5=malloc(sizeof(int));
 +
// esta variável é alocada na pilha no entanto, aponta para onde é alocada dinamicamente pelo bloco no heap.
 +
return 0;
 +
// stack frame para a função principal é destruída depois de executado o programa principal.
 +
}
 +
</syntaxhighlight>
 +
 
 +
===Usando a ferramenta '''nm'''===
 +
Há várias ferramentas para verificar onde uma variável é armazenada na memória. Mas a ferramenta fácil de usar é '''nm'''. Compile o programa acima (EXEMPLO 2) como indicado abaixo:
 +
 
 +
;Usando a ferramenta nm
 +
:$ gcc codigo.c -o teste
 +
:$ nm ./teste
 +
 
 +
Se nenhum argumento for passado para nm, o programa assume a entrada como a.out e vamos obter alguma saída como abaixo.
 +
 
 +
<code>
 +
08049f28 d _DYNAMIC
 +
08049ff4 d _GLOBAL_OFFSET_TABLE_
 +
080484dc R _IO_stdin_used
 +
        w _Jv_RegisterClasses
 +
08049f18 d __CTOR_END__
 +
08049f14 d __CTOR_LIST__
 +
08049f20 D __DTOR_END__
 +
08049f1c d __DTOR_LIST__
 +
080485e0 r __FRAME_END__
 +
08049f24 d __JCR_END__
 +
08049f24 d __JCR_LIST__
 +
0804a020 A __bss_start
 +
0804a00c D __data_start
 +
08048490 t __do_global_ctors_aux
 +
08048360 t __do_global_dtors_aux
 +
0804a010 D __dso_handle
 +
        w __gmon_start__
 +
08048482 T __i686.get_pc_thunk.bx
 +
08049f14 d __init_array_end
 +
08049f14 d __init_array_start
 +
08048480 T __libc_csu_fini
 +
08048410 T __libc_csu_init
 +
        U __libc_start_main@@GLIBC_2.0
 +
0804a020 A _edata
 +
0804a044 A _end
 +
080484bc T _fini
 +
080484d8 R _fp_hw
 +
080482b4 T _init
 +
08048330 T _start
 +
0804a040 B bss1
 +
0804a030 b bss2
 +
0804a03c B bss3
 +
0804a020 b completed.6159
 +
0804a00c W data_start
 +
0804a024 b dtor_idx.6161
 +
080483c0 t frame_dummy
 +
0804a028 B init1
 +
0804a014 D init2
 +
0804a018 D init3
 +
0804a038 b local3.1236
 +
0804a01c d local4.1237
 +
080483e4 T main
 +
        U malloc@@GLIBC_2.0
 +
</syntaxhighlight>
 +
 
 +
Os números são os valores de um símbolo, seguido do tipo de símbolo (apresentado como uma letra) e o nome do símbolo.
 +
O tipo de símbolo requer mais explicações:  Uma letra '''minúsculas''' significa que é '''variável local''' e '''maiúsculas''' significa '''global''' (externamente disponíveis a partir do arquivo).
 +
:B Seção de dados não inicializados (BSS)
 +
:D Seção de dados inicializados
 +
:T Seção de texto/código
 +
:U não identificado
 +
 
 +
==Alocando uma estrutura ==
  
 
<syntaxhighlight lang=c>
 
<syntaxhighlight lang=c>
Linha 92: Linha 228:
 
    
 
    
 
   teste=NULL;
 
   teste=NULL;
 +
}
 
</syntaxhighlight>
 
</syntaxhighlight>
  
===Usando o typedef para ajudar na definição e declaração de estruturas===
+
==Usando o ''typedef'' para ajudar na definição e declaração de estruturas==
  
 
<syntaxhighlight lang=c>
 
<syntaxhighlight lang=c>
Linha 126: Linha 263:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
===Alocando dinamicamente uma tabela de estruturas===
+
==Alocando dinamicamente uma tabela de estruturas==
  
  
Linha 160: Linha 297:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Exercício:  
+
;EXERCÍCIO: Refazer o exemplo anterior para que a quantidade de memória a ser alocada pela tabela seja passada na linha de comando.
 
 
Refazer o exemplo anterior para que a quantidade de memória a ser alocada pela tabela seja passada na linha de comando.
 
 
 
 
 
 
 
 
 
  
  
Linha 174: Linha 305:
 
! style="background: #cdc5bf;" | [[AULA 18 - Programação 1 - Graduação | << ]]
 
! style="background: #cdc5bf;" | [[AULA 18 - Programação 1 - Graduação | << ]]
 
! style="background: #cdc5bf;" | Aula 19
 
! style="background: #cdc5bf;" | Aula 19
! style="background: #cdc5bf;" | [[PRG1-_Programação_I_-_Graduação | <> ]]
+
! style="background: #cdc5bf;" | [[AULA 20 - Programação 1 - Graduação | >> ]]
 
|}
 
|}

Edição atual tal como às 10h07min de 26 de maio de 2015

Alocação Dinâmica de Memória

Objetivos

  • Anatomia de um programa em execução;
  • Alocação dinâmica de memória.

A área de heap e o layout de memória de um programa C

Neste link podemos ter uma ideia da anatomia de um programa na memória do computador.

http://shivacherukuri.blogspot.com.br/2011/03/memory-layout-in-cdata-segmentbss-code.html

Podemos observar que existe as seguintes áreas:

  • TEXT: área onde está o código;
  • BSS: dados estaticamente alocados e não inicializados;
  • DATA: dados estaticamente alocados e inicializados;
  • STACK: área de pilha (variáveis locais);
  • HEAP: área de dados alocados dinamicamente.

Quando declaramos uma variável global da forma:

 int x;

a variável x é alocada em uma área chamada BSS (dados não incializados). Note que x possui uma área de memória reservada a ela (4 bytes) e cuja existência é o tempo de vida do programa em execução.

Da mesma forma, uma variável global da forma:

 int y=10;

é alocada na área de DATA. A inicialização é definida normalmente na carga do programa. Os valores de inicialização são copiados para a área de DATA na carga do programa, a partir do arquivo executável.

Por vezes, o tamanho dos dados não são conhecidos antes da execução do programa. Neste caso, pode ser interessante criá-los dinamicamente e é neste ponto que entra a área de HEAP. Trata-se de uma área de memória, gerenciada a partir de funções da biblioteca do C.

As funções mais conhecidas são (http://en.wikipedia.org/wiki/C_dynamic_memory_allocation):

  • malloc: aloca n bytes de memória;
  • free: libera memória;
  • realloc: realoca memória
  • calloc: aloca n bytes de memória e zera.

http://www.linuxjournal.com/article/4681 http://www.cs.cmu.edu/~guna/15-123S11/Lectures/Lecture08.pdf

EXEMPLO 1
Alocação dinâmica de números inteiros (exercício puramente didático):
#include <stdlib.h>

main()
{
  int *px, *py;
  int resultado;
  px = (int *) malloc(sizeof(int));
  *px = 5;
  py = (int *) malloc(sizeof(int));
  *py = 2;
  resultado = *px + *py;

  free (px);
  px = NULL;
  free (py);
  py = NULL;
}
EXEMPLO 2
Diferente da função malloc, calloc além de inicializar os espaços de memória ainda atribui o valor 0 (zero) para cada um deles.
#include <stdio.h>
#include <stdlib.h>
 
int main(void){
 
    int *valores, *aux;
    int qtd, i, vlr;
 
    printf("\nEntre com a quantidade de números: ");
    scanf("%d", &qtd);
 
    if(qtd == 0)
        exit(0);

//Aloca um vetor com a quantidade recebida em qtd
    valores = (int *) calloc(qtd, sizeof (int));

//Imprime o endereco e valor (zero) para a quantidade de números informada
    aux = valores;
    for(i = 1; i <= qtd; i++){
        printf("%p\t%d\n", aux, *aux);
        aux++;
    }
 
    aux = valores; //Ponteiro para o primeiro espaço de memória
    for(i = 1; i <= qtd; i++){
        printf("Digite o número %d ->: ", i);
        scanf("%d", &vlr);
        *aux = vlr;
        aux++;
    }
 
    aux = valores; //Retorna à posição inicial no mapa de memória
    for(i = 1; i <= qtd; i++){
        printf("%p\t%d\n", aux, *aux);
        aux++;
    }
 
    free(valores);
 
    return 0;
}


EXEMPLO 3
Vejamos comos diferentes elementos do programa são armazenados quando esse programa é executado. Os comentários no código explicam onde as variáveis ficam armazenadas.
int bss1;
static double bss2;
char *bss3;
// estas variáveis são armazenadas no segmento de dados não inicializado (BSS)
int init1=0;
float init2=10.0;
char *init3="Alo mundo!";
// estas variáveis são armazenadas no segmento de dados inicializados (DATA)
// o código para função principal é armazenado em (code segment)
int main()
{
	int local1=10; // esta variável é armazenada na pilha (stack) e código de inicialização é gerado pelo compilador.
	int local2; //esta variável não é inicializada, portanto, tem valor de lixo. Ela não fica inicializada com zero.
	static int local3; // esta é alocada no segmento BSS e é inicializada com zero.
	static int local4=100; //este é alocada e inicializada no segmento de dados
	int *local5=malloc(sizeof(int));
// esta variável é alocada na pilha no entanto, aponta para onde é alocada dinamicamente pelo bloco no heap.
return 0;
// stack frame para a função principal é destruída depois de executado o programa principal.
}

Usando a ferramenta nm

Há várias ferramentas para verificar onde uma variável é armazenada na memória. Mas a ferramenta fácil de usar é nm. Compile o programa acima (EXEMPLO 2) como indicado abaixo:

Usando a ferramenta nm
$ gcc codigo.c -o teste
$ nm ./teste

Se nenhum argumento for passado para nm, o programa assume a entrada como a.out e vamos obter alguma saída como abaixo.

08049f28 d _DYNAMIC 08049ff4 d _GLOBAL_OFFSET_TABLE_ 080484dc R _IO_stdin_used

        w _Jv_RegisterClasses

08049f18 d __CTOR_END__ 08049f14 d __CTOR_LIST__ 08049f20 D __DTOR_END__ 08049f1c d __DTOR_LIST__ 080485e0 r __FRAME_END__ 08049f24 d __JCR_END__ 08049f24 d __JCR_LIST__ 0804a020 A __bss_start 0804a00c D __data_start 08048490 t __do_global_ctors_aux 08048360 t __do_global_dtors_aux 0804a010 D __dso_handle

        w __gmon_start__

08048482 T __i686.get_pc_thunk.bx 08049f14 d __init_array_end 08049f14 d __init_array_start 08048480 T __libc_csu_fini 08048410 T __libc_csu_init

        U __libc_start_main@@GLIBC_2.0

0804a020 A _edata 0804a044 A _end 080484bc T _fini 080484d8 R _fp_hw 080482b4 T _init 08048330 T _start 0804a040 B bss1 0804a030 b bss2 0804a03c B bss3 0804a020 b completed.6159 0804a00c W data_start 0804a024 b dtor_idx.6161 080483c0 t frame_dummy 0804a028 B init1 0804a014 D init2 0804a018 D init3 0804a038 b local3.1236 0804a01c d local4.1237 080483e4 T main

        U malloc@@GLIBC_2.0

</syntaxhighlight>

Os números são os valores de um símbolo, seguido do tipo de símbolo (apresentado como uma letra) e o nome do símbolo. O tipo de símbolo requer mais explicações: Uma letra minúsculas significa que é variável local e maiúsculas significa global (externamente disponíveis a partir do arquivo).

B Seção de dados não inicializados (BSS)
D Seção de dados inicializados
T Seção de texto/código
U não identificado

Alocando uma estrutura

#include <stdio.h>
#include <stdlib.h>
 
void main()
{
  struct TTeste{
     int x;
     int y;
  };
  
  struct TTeste *teste;
  

  
  teste = (struct TTeste *) malloc (sizeof(struct TTeste));
  if (teste==NULL) {
      printf("erro de alocação");
      exit(1);
  }
  
  teste->x=10;
  
  free(teste);
  
  teste=NULL;
}

Usando o typedef para ajudar na definição e declaração de estruturas

#include <stdio.h>
#include <stdlib.h>
 
void main()
{
  typedef struct {
     int x;
     int y;
  } TTeste;
  
  TTeste *teste;
  

  
  teste = (TTeste *) malloc (sizeof(TTeste));
  if (teste==NULL) {
      printf("erro de alocação");
      exit(1);
  }
  
  teste->x=10;
  
  free(teste);
  
  teste=NULL;
  
}

Alocando dinamicamente uma tabela de estruturas

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

void main()
{
  struct TTeste{
     int x;
     int y;
  } *teste;

  if ((teste = (struct TTeste *) malloc (100*sizeof(struct TTeste)))==NULL) {
      printf("erro de alocação");
      exit(1);
  }



  teste[10].x= 5;

  if ((teste = realloc(teste, 10000*sizeof(struct TTeste)))==NULL) {
      printf("erro de alocação");
      exit(1);
  }

  teste[9000].x=20;
  free(teste);

}
EXERCÍCIO
Refazer o exemplo anterior para que a quantidade de memória a ser alocada pela tabela seja passada na linha de comando.



<< Aula 19 >>