1 / 38

Estruturas de Dados - T.332 Capítulo 3 Parte 2: Alocação Dinâmica de Memória

Estruturas de Dados - T.332 Capítulo 3 Parte 2: Alocação Dinâmica de Memória. 3.1 As Funções de Alocação Dinâmica de Memória em "C". Alocação Dinâmica é um meio pelo qual o programa pode obter memória enquanto está em execução. Já visto até agora:

rimona
Download Presentation

Estruturas de Dados - T.332 Capítulo 3 Parte 2: Alocação Dinâmica de Memória

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Estruturas de Dados - T.332Capítulo 3Parte 2:Alocação Dinâmica de Memória

  2. 3.1 As Funções de Alocação Dinâmica de Memória em "C" • Alocação Dinâmica é um meio pelo qual o programa pode obter memória enquanto está em execução. • Já visto até agora: • Constantes são "codificadas" dentro do código objeto de um programa em tempo de compilação. • Variáveis globais (estáticas) têm a sua alocação codificada em tempo de compilação e são alocadas logo que um programa inicia a execução. • Variáveis locais em funções (ou métodos) são alocadas através da requisição de espaço na pilha (stack).

  3. Topo da Memória StackPointer Inicio da Pilha • Programa: #include <stdio.h> char *a, *b; int func_A () { int local1, local2; - - - } void func_B () { int localA, localB; localA = func_A(); localB = func_A(); } main () { a = "Essa aula é legal"; b = "Será mesmo?" func_B(); } HeapPointer Início da Área Alocável a b Variáveis estáticas 10010101... P r o g r a m a Código objeto "Essa aula é ... "Será mesmo.. Constantes Sist.Operacional Base da Memória

  4. Programa: • #include <stdio.h> • char *a, *b; • int func_A () • { • int local1, local2; • - - - • } • void func_B () • { • int localA, localB; • localA = func_A(); • localB = func_A(); • } • main () • { • a = "Essa aula é legal"; • b = "Será mesmo?" • func_B(); • } Topo da Memória StackPointer Inicio da Pilha HeapPointer Início da Área Alocável a b Variáveis estáticas 10010101... Código objeto "Essa aula é ... "Será mesmo.. Constantes Sist.Operacional Base da Memória

  5. Programa: • #include <stdio.h> • char *a, *b; • int func_A () • { • int local1, local2; • - - - • } • void func_B () • { • int localA, localB; • localA = func_A(); • localB = func_A(); • } • main () • { • a = "Essa aula é legal"; • b = "Será mesmo?" • func_B(); • } Topo da Memória StackPointer Topo da Pilha HeapPointer Topo da Área Alocável a b Variáveis estáticas 10010101... Código objeto "Essa aula é ... "Será mesmo.. Constantes Sist.Operacional Base da Memória

  6. Programa: • #include <stdio.h> • char *a, *b; • int func_A () • { • int local1, local2; • - - - • } • void func_B () • { • int localA, localB; • localA = func_A(); • localB = func_A(); • } • main () • { • a = "Essa aula é legal"; • b = "Será mesmo?" • func_B(); • } StackPointer Topo da Pilha Topo da Memória &main-#3 localA localB HeapPointer Topo da Área Alocável a b Variáveis estáticas 10010101... Código objeto "Essa aula é ... "Será mesmo.. Constantes Sist.Operacional Base da Memória

  7. Programa: • #include <stdio.h> • char *a, *b; • int func_A () • { • int local1, local2; • - - - • } • void func_B () • { • int localA, localB; • localA = func_A(); • localB = func_A(); • } • main () • { • a = "Essa aula é legal"; • b = "Será mesmo?" • func_B(); • } StackPointer Topo da Pilha Topo da Memória &main-#3 localA localB HeapPointer Topo da Área Alocável a b Variáveis estáticas 10010101... Código objeto "Essa aula é ... "Será mesmo.. Constantes Sist.Operacional Base da Memória

  8. Programa: • #include <stdio.h> • char *a, *b; • int func_A () • { • int local1, local2; • - - - • } • void func_B () • { • int localA, localB; • localA = func_A(); • localB = func_A(); • } • main () • { • a = "Essa aula é legal"; • b = "Será mesmo?" • func_B(); • } StackPointer Topo da Pilha Topo da Memória &main-#3 localA localB &func_B-#2 local1 local2 HeapPointer Topo da Área Alocável a b Variáveis estáticas 10010101... Código objeto "Essa aula é ... "Será mesmo.. Constantes Sist.Operacional Base da Memória

  9. Programa: • #include <stdio.h> • char *a, *b; • int func_A () • { • int local1, local2; • - - - • } • void func_B () • { • int localA, localB; • localA = func_A(); • localB = func_A(); • } • main () • { • a = "Essa aula é legal"; • b = "Será mesmo?" • func_B(); • } StackPointer Topo da Pilha Topo da Memória &main-#3 localA localB &func_B-#2 local1 local2 HeapPointer Topo da Área Alocável a b Variáveis estáticas 10010101... Código objeto "Essa aula é ... "Será mesmo.. Constantes Sist.Operacional Base da Memória

  10. Programa: • #include <stdio.h> • char *a, *b; • int func_A () • { • int local1, local2; • - - - • } • void func_B () • { • int localA, localB; • localA = func_A(); • localB = func_A(); • } • main () • { • a = "Essa aula é legal"; • b = "Será mesmo?" • func_B(); • } StackPointer Topo da Pilha Topo da Memória &main-#3 localA localB HeapPointer Topo da Área Alocável a b Variáveis estáticas 10010101... Código objeto "Essa aula é ... "Será mesmo.. Constantes Sist.Operacional Base da Memória

  11. Programa: • #include <stdio.h> • char *a, *b; • int func_A () • { • int local1, local2; • - - - • } • void func_B () • { • int localA, localB; • localA = func_A(); • localB = func_A(); • } • main () • { • a = "Essa aula é legal"; • b = "Será mesmo?" • func_B(); • } StackPointer Topo da Pilha Topo da Memória &main-#3 localA localB &func_B-#3 local1 local2 HeapPointer Topo da Área Alocável a b Variáveis estáticas 10010101... Código objeto "Essa aula é ... "Será mesmo.. Constantes Sist.Operacional Base da Memória

  12. Programa: • #include <stdio.h> • char *a, *b; • int func_A () • { • int local1, local2; • - - - • } • void func_B () • { • int localA, localB; • localA = func_A(); • localB = func_A(); • } • main () • { • a = "Essa aula é legal"; • b = "Será mesmo?" • func_B(); • } StackPointer Topo da Pilha Topo da Memória &main-#3 localA localB &func_B-#2 local1 local2 HeapPointer Topo da Área Alocável a b Variáveis estáticas 10010101... Código objeto "Essa aula é ... "Será mesmo.. Constantes Sist.Operacional Base da Memória

  13. Programa: • #include <stdio.h> • char *a, *b; • int func_A () • { • int local1, local2; • - - - • } • void func_B () • { • int localA, localB; • localA = func_A(); • localB = func_A(); • } • main () • { • a = "Essa aula é legal"; • b = "Será mesmo?" • func_B(); • } StackPointer Topo da Pilha Topo da Memória &main-#3 localA localB HeapPointer Topo da Área Alocável a b Variáveis estáticas 10010101... Código objeto "Essa aula é ... "Será mesmo.. Constantes Sist.Operacional Base da Memória

  14. Programa: • #include <stdio.h> • char *a, *b; • int func_A () • { • int local1, local2; • - - - • } • void func_B () • { • int localA, localB; • localA = func_A(); • localB = func_A(); • } • main () • { • a = "Essa aula é legal"; • b = "Será mesmo?" • func_B(); • } Topo da Memória StackPointer Topo da Pilha HeapPointer Topo da Área Alocável a b Variáveis estáticas 10010101... Código objeto "Essa aula é ... "Será mesmo.. Constantes Sist.Operacional Base da Memória

  15. Alocação Dinâmica em "C" • A memória alocada pelas funções de alocação dinâmica é obtida do heap. • O heap é a região de memória livre que se encontra entre o programa (com a área de armazenamento permanente) e a pilha (stack). • O tamanho do heap é, a princípio, desconhecido do programa. • "C" possui duas funções básicas para gerência de memória: • malloc(nº de bytes)- aloca memória. • free(endereço)- libera memória

  16. Função malloc(): • Protótipo: void *malloc(size_t número_de_bytes); • Detalhes : • Devolve um ponteiro do tipo void (sem tipo) para o início (1º byte) da área de memória alocada. • Isto significa que o valor deste ponteiro pode ser atribuído a qualquer variável do tipo ponteiro. • Para isto deve ser utilizado sempre um typecasting. Ex.: se x é ponteiro para inteiro então explicitar isto comx = (int *) malloc( sizeof(int) ); • número_de_bytes é a quantidade de bytes alocada. • Se a memória for alocada no topo do heap, o heapPointer é atualizado (incrementado de número_de_bytes). • O tipo size_t é definido em stdlib.h.

  17. HeapPointer Topo da Área Alocável Topo da Memória StackPointer Topo da Pilha • Exemplo: • #include <stdlib.h> • #include <stdio.h> • char *p; • int *q; • main () • { • p = (char *) malloc(1000); • // Aloca 1000 • // bytes de RAM • q = (int *) malloc(50*sizeof(int)); • // Aloca espaço • // para 50 inteiros. • } 50*int = 200 bytes 1000 bytes p q Variáveis estáticas 10010101... Código objeto Constantes Sist.Operacional Base da Memória

  18. malloc devolve: • um ponteiro para a área alocada • o ponteiro nulo (NULL) caso não seja possível alocar a memória requisitada. • Convém verificar se foi pos-sível alocar a memória: • #include <stdio.h> • #include <stdlib.h> • char *p; • main () • { ................ • p = malloc(1000) • // Tenta alocar 1000 • // bytes de RAM • if (p == NULL) • // Testa se p • // diferente de 0 • printf("Sem memória."); • } Topo da Memória Espaço de variáveis locais alocado StackPointer Topo da Pilha HeapPointer Topo da Área Alocável Já alocado antes p Variáveis estáticas 10010101... Código objeto "Sem memória" Constantes Sist.Operacional Base da Memória

  19. Função free: • Protótipo: void free( void *p ); • Detalhes : • Devolve memória previamente alocada ao sistema. • A memória devolvida é aquela que foi alocada com um ponteiro com o valor de p. • O valor de pdeve ser um valor que foi alguma vez retornado por malloc(). • Não é possível alocar-se um vetor enorme e depois dealocar-se a parte dele que "sobrou". • A utilização de free() com um valor de ponteiro qualquer poder ter resultados catastróficos. • A gerência de buracos no heap é responsabilidade do sistema operacional.

  20. Exercício: Lista com um vetor de Ponteiros para Strings. • Uma lista ordenada pode conter Strings de qualquercomprimento < 10000. • Esta lista tem número de elementos máximo fixo = 100 e é implementada como um vetor de ponteiros para Strings. • Utilize as rotinas de lista com vetor que você utilizou para a agenda. • Um novo String é lido primeiramente para dentro de uma variável auxiliar qualquer. • Então é alocada memória para exatamente o seu tamanho e ele é copiado para esta área. Para copiar um String utilize strcpy(). • Por fim um lugar na lista é encontrado para ele. A posição escolhida do vetor de ponteiros da lista é instanciada através da atualização dos valores do ponteiro da posição do string na lista com o endereço do string.

  21. Modelagem da estrutura Strings lidos do usuário e alocados no Heap C o n s t i t u i r \0 Lista com Vetor de Ponteiros -1 0 1 2 3 4 1 S a b ã o \0

  22. Modelagem da Lista • Pseudo-código: constantes Maxlista = 100; tipo Lista { caracter *dados[Maxlista]; “ Vetor de ponteiros para char “ inteiro ultimo; }; • Importante: Observe que criando uma variável do tipo Lista você não vai estar alocando memória para os strings a serem lidos, apenas para os ponteiros para eles.

  23. Topo da Memória StackPointer Topo da Pilha • Organização de memória do Exercício: Espaço de variáveis locais alocado HeapPointer Topo da Área Alocável str4 str3 str2 str1 Vetor de char* Var.Estáticas 10010101... Código objeto Constantes Sist.Operacional Base da Memória

  24. Para verificar o comprimento de um String: • Utilize a função strlen(). • Esta função devolve o comprimento (em caracteres imprimíveis) de um String. • Protótipo: int strlen(char *p); • #include <stdio.h> • #include <stdlib.h> • #include <sting.h> • char p[90] = "Carro"; • main () • { • printf("%i", strlen(p) ); • } • Imprime: 5.

  25. Para copiar um String: • Utilize a função strcpy(). • Esta função copia o conteúdo de um string (dado por um apontador) para a posição de memória dada por outro apontador. • Protótipo: char *strcpy(char *destino, *fonte); • #include <stdio.h> • #include <stdlib.h> • #include <sting.h> • char p[90] = "Carro"; • char lata[20]; • main () • { • strcpy(lata, p) ); • printf("s%", lata); • } • Imprime: Carro.

  26. Detalhes: Lista Ordenada com um vetor de ponteiros para Strings. • Como você não sabe o comprimento do String que o usuário vai digitar, use primeiro uma variável auxiliar grande (10000 posições) para guardar o que foi digitado. • A lista deve ser passada como parâmetro para todas as funções que a utilizam. • Da mesma maneira as variáveis de controle da lista. • Todas as funções de lista ordenada implementadas anteriormente devem ser reimplementadas para utilizar estes Strings. • Para a leitura de um String utilize scanf("%s", entrada) onde char entrada[10000].

  27. Exercício Nº 2: Trabalho com Passagem de Parâmetros • Agora você vai fazer um programa que manipula mais de uma lista. • O programa fará isto com um único conjunto de funções e passagem das diversas listas como parâmetros. • Como aplicação imaginemos um sistema de contabilidade simples. • Você vai ter um Plano de Contas constituído por duas listas: débitos e créditos. • O mesmo conjunto de funções (que você já implementou) vai poder ser utilizado para isso: você somente precisa ampliar o conjunto de parâmetros da função para passar por referência também a lista que você quer alterar. • A passagem de parâmetro da lista deve ser por referência porque você deseja que as alterações sejam persistentes.

  28. Modelagem de um Lancamento • Cada lista de débitos ou créditos é constituida de um lançamento. O lançamento possui: • Um valor real (positivo). • Um nome, por exemplo “pagar proteção à Mafia” • Estrutura: tipo Lancamento { caracter*nome; “ponteiro para char alocado no heap“ real valor; };

  29. Modelagem de um tipo Lista para Débitos ou Créditos • Pseudo-código: constantes Maxlista = 100; tipo ListaContabil { Lancamento dados[Maxlista]; “ Vetor de Estrutura Lançamento “ inteiro ultimo; }; • Importante: Observe que criando um vetro de lancamentos, você não vai estar reservando memória para os nomes destes, pois o campo nome é só ponteiros. Lembre-se de alocar.

  30. Usando (pseudo código) • Crie variáveis globais: ListaContabil debitos, creditos; • Passe estas variáveis como parâmetro por referência: adiciona(&debitos, nomeLanc, valorLanc) • Cabeçalho: Inteiro FUNÇÃO adiciona(ListaContabil *plano; caracter *nome; real valor) • Importante: nome é passado como ponteiro para caracter. Use um buffer global para ler o nome do lancamento do usuário.

  31. Desenho Strings lidos do usuário e alocados no Heap Lista de debitos ou de créditos com Vetor de Estruturas do tipo Lançamento -1 0 1 2 3 4 1 R$ 5,00 S a b ã o \0 R$ 505,00 P a s s a g e n s \0

  32. Usando (código C) • Referencie diferentemente se estiver usando ponteiros para a lista ou a lista diretamente: ListaContabil debitos, creditos; debitos.dados[2].valor = 5.0; strcpy(debitos.dados[2].nome, buffer); Dentro das funções: Suponha: ListaContabil *ponteiro e ponteiro = &debitos; ponteiro->dados[2].valor = 5.0; strcpy(ponteiro->dados[2].nome, buffer);

  33. Headerfile: Como Garantir Inclusão Única /* Arquivo: pilha.h */ #ifndef EstruturaDaPilha #define EstruturaDaPilha /* Definir uma estrutura para a pilha */ struct estruturaDaPilha { int topo; int dados[MaxPilha]; }; /* Def. um tipo que tem a estrutura da pilha. */ typedef struct estruturaDaPilha pilha; #endif

  34. Headerfiles: Importante • A diretiva de compilação #ifndef (if not defined) diz que aquela área de código fonte entre o #ifndef e o #endif somente será levada em conta pelo compilador se o argumento de #ifndef ainda não houver sido definido na mesma sessão de compilação no escopo de um módulo. • Isso garante que código que a gente "por via das duvidas" inclui mais de uma vez em um modulo não seja considerado duas vezes. • Um exemplo de como isto e útil esta na diretiva #include <stdio.h> que esta presente tanto em pilha.h como em pilha.c como em aplic.c. • Como aplic.c carrega pilha.h "para dentro" de si mesmo, carregara também stdio.h. Como está explicitamente também carregando stdio.h, se não houver uma diretiva #ifndef em stdio.h, ele terá o mesmo código existente em stdio.h duas vezes.

  35. Projetos de Implementação: Usando Make • Make: Utilitário que auxilia a compilação de projetos formados por vários arquivos de programas • Realiza checagem de dependências entre o arquivo destino e os fontes • Baseia-se nas datas de arquivos

  36. Projetos de Implementação: Sintaxe do Makefile aplic: aplic.o pilha.o gcc -g -o aplic aplic.o pilha.o aplic.o: aplic.c pilha.h gcc -g - c aplic.c pilha.o: pilha.c pilha.h gcc -g -c pilha.c meta: dependencia1 dependênciaN <tab>um comando para atingir meta <tab>outro comando para atingir meta

  37. Projetos de Implementação: Usando o Makefile • Chamada: make -f <nome do Makefile> • Se o nome não for dado, make procurará por arquivos chamados Makefile e makefile, nesta ordem. • Para definir qual meta será a primeira a ser considerada: • Se você não diz nada, a primeira meta será considerada. • Voce pode passar como último parâmetro o nome da meta: make -f meuMakefile compilar • Todas as dependencias de compilar, se esta meta existir, serão também levadas em consideração.

  38. Módulo lista.h: • #ifndef Lista • #define Lista • typedef struct estruLista { • char *elemento[30]; • int ultimo; • int max; • }; • typedef struct estruLista lista; • #endif • Módulo lista.c: • #include <stdio.h> • #include <stdlib.h> • #include “lista.h” • lista *criaLista () • { • lista *nova; • nova = malloc( sizeof(lista) ); • nova->max = 30; • nova->ultimo = -1; • return (nova); • } • void destroiLista(lista *morta) • { • // Libera memória p/os strings • for (i=0; morta->ultimo; i++) • free (morta->elemento[i]); • // Libera memória da lista • free ( morta ); • }

More Related