2. 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. a
b
10010101...
"Essa aula é ...
"Será mesmo..
Sistema Operacional
HeapPointer
Início da Área
Alocável
StackPointer
Início da Pilha
Topo da Memória
Base da Memória
P
r
o
g
r
a
m
a
Variáveis estáticas
Código objeto
Constantes
#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();
}
4. a
b
10010101...
"Essa aula é ...
"Será mesmo..
Sistema Operacional
HeapPointer
Início da Área
Alocável
StackPointer
Início da Pilha
Topo da Memória
Base da Memória
Variáveis estáticas
Código objeto
Constantes
#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();
}
5. a
b
10010101...
"Essa aula é ...
"Será mesmo..
Sistema Operacional
HeapPointer
Início da Área
Alocável
StackPointer
Início da Pilha
Topo da Memória
Base da Memória
Variáveis estáticas
Código objeto
Constantes
#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();
}
6. a
b
10010101...
"Essa aula é ...
"Será mesmo..
Sistema Operacional
HeapPointer
Início da Área
Alocável
StackPointer
Início da Pilha
Topo da Memória
Base da Memória
Variáveis estáticas
Código objeto
Constantes
#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();
}
&main-#3
localA
localB
7. a
b
10010101...
"Essa aula é ...
"Será mesmo..
Sistema Operacional
HeapPointer
Início da Área
Alocável
StackPointer
Início da Pilha
Topo da Memória
Base da Memória
Variáveis estáticas
Código objeto
Constantes
#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();
}
&main-#3
localA
localB
8. a
b
10010101...
"Essa aula é ...
"Será mesmo..
Sistema Operacional
HeapPointer
Início da Área
Alocável
StackPointer
Início da Pilha
Topo da Memória
Base da Memória
Variáveis estáticas
Código objeto
Constantes
#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();
}
&main-#3
localA
localB
&func_B-#2
local1
local2
9. a
b
10010101...
"Essa aula é ...
"Será mesmo..
Sistema Operacional
HeapPointer
Início da Área
Alocável
StackPointer
Início da Pilha
Topo da Memória
Base da Memória
Variáveis estáticas
Código objeto
Constantes
#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();
}
&main-#3
localA
localB
&func_B-#2
local1
local2
10. a
b
10010101...
"Essa aula é ...
"Será mesmo..
Sistema Operacional
HeapPointer
Início da Área
Alocável
StackPointer
Início da Pilha
Topo da Memória
Base da Memória
Variáveis estáticas
Código objeto
Constantes
#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();
}
&main-#3
localA
localB
11. a
b
10010101...
"Essa aula é ...
"Será mesmo..
Sistema Operacional
HeapPointer
Início da Área
Alocável
StackPointer
Início da Pilha
Topo da Memória
Base da Memória
Variáveis estáticas
Código objeto
Constantes
#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();
}
&main-#3
localA
localB
&func_B-#3
local1
local2
12. a
b
10010101...
"Essa aula é ...
"Será mesmo..
Sistema Operacional
HeapPointer
Início da Área
Alocável
StackPointer
Início da Pilha
Topo da Memória
Base da Memória
Variáveis estáticas
Código objeto
Constantes
#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();
}
&main-#3
localA
localB
&func_B-#3
local1
local2
13. a
b
10010101...
"Essa aula é ...
"Será mesmo..
Sistema Operacional
HeapPointer
Início da Área
Alocável
StackPointer
Início da Pilha
Topo da Memória
Base da Memória
Variáveis estáticas
Código objeto
Constantes
#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();
}
&main-#3
localA
localB
14. a
b
10010101...
"Essa aula é ...
"Será mesmo..
Sistema Operacional
HeapPointer
Início da Área
Alocável
StackPointer
Início da Pilha
Topo da Memória
Base da Memória
Variáveis estáticas
Código objeto
Constantes
#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();
}
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 dois operadores básicos para
gerência de memória:
– new(nº de bytes) - aloca memória.
– delete(endereço) - libera memória.
16. Operador new
• Protótipo:
void* operator new(size_t número_de_bytes);
• Detalhes:
– devolve um ponteiro do tipo do tipo alocado para o início (1º
byte) da área de memória alocada;
– 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. char *p;
int *q;
main() {
// Aloca 1000 bytes de RAM.
p=(char *) operator new(1000);
// Aloca espaço para 50
// inteiros.
q = new int[50];
}
Sist.Operacional
10010101...
p
q
HeapPointer
Topo da Área
Alocável
StackPointer
Topo da Pilha
Topo da Memória
Base da Memória
Variáveis estáticas
Código objeto
Constantes
1000 bytes
50*int = 200 bytes
18. Operador delete
• Protótipo:
void delete( 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 p deve ser um valor que foi alguma vez retornado por
new;
• não é possível alocar um vetor enorme e depois desalocar a
parte dele que "sobrou“;
– a gerência de buracos no heap é responsabilidade do
sistema operacional.
19. Exercício:
Lista com um vetor de Ponteiros para Strings
• Uma lista ordenada pode conter Strings de qualquer
comprimento < 10000;
• esta lista tem um 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ê implementou
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.
20. Modelagem da estrutura
1
Lista com
Vetor de
Ponteiros
Strings lidos
do usuário
e alocados
no Heap
S a b ã o 0
C o n s t i t u i r 0
21. Modelagem da Lista
• Pseudo-código:
constantes MAXLISTA = 100;
Classe Lista {
// Vetor de ponteiros para caracter.
caracter *dados[MAXLISTA];
inteiro último;
};
22. Organização de
memória para o
exercício
Sist.Operacional
10010101...
HeapPointer
Topo da Área
Alocável
StackPointer
Topo da Pilha
Topo da Memória
Base da Memória
Código objeto
Constantes
str4
str3
str2
str1
Espaço de variáveis
locais alocado
Var.Estáticas
23. • 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
24. • 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, char *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
25. 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;
• Todas os métodos de lista ordenada implementadas
anteriormente devem ser reimplementadas para
utilizar estes Strings;
• para a leitura de um String utilize scanf("%s",
entrada).
26. Exercício 2:
Trabalho com Passagem de Parâmetros
• Agora você vai fazer um programa que manipula mais de uma
lista;
• 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 Classes (que você já implementou) vai
poder ser utilizado para isso.
27. Modelagem de um Lançamento
• Cada lista de débitos ou créditos é constituída
por lançamentos. Cada lançamento possui:
– um valor real (positivo);
– um nome. Por exemplo, “Pagar proteção à Mafia”
• Estrutura:
Classe Lançamento {
caracter *nome;
real valor;
};
28. Modelagem de um tipo Lista para
Débitos ou Créditos
• Pseudo-código:
constantes MAXLISTA = 100;
Classe ListaContábil {
Lançamento dados[MAXLISTA];
inteiro último;
};
29. Usando (pseudo-código)
• Crie variáveis globais:
ListaContábil débitos, créditos;
• Passe estas variáveis como parâmetros por
referência:
adiciona(&débitos, nomeLanc, valorLanc);
• Cabeçalho:
Inteiro FUNÇÃO adiciona(tListaContábil *plano;
caracter *nome;
real valor);
• Importante: nome é passado como ponteiro para
caracter. Use um buffer global para ler o nome do
lançamento do usuário.
30. Modelagem da estrutura
1
Lista de débitos ou
de créditos com Vetor
de Estruturas do tipo
Lançamento
Strings lidos
do usuário
e alocados
no Heap
S a b ã o 0
P a s s a g e n s 0
R$ 5,00
R$ 505,00
31. 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);
32. Headerfile: como garantir Inclusão Única
// Arquivo: pilha.h
#ifndef EstruturaDaPilha
#define EstruturaDaPilha
// Definir uma estrutura para a pilha.
class estruturaDaPilha {
int topo;
int dados[MAXPILHA];
};
// Define um tipo que tem a estrutura da
// pilha.
#endif
33. 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 dúvidas" inclui
mais de uma vez em um módulo não seja considerado duas
vezes;
• um exemplo de como isto é útil está na diretiva #include
<stdio.h> que está presente tanto em pilha.h quanto em
pilha.cpp e em aplic.cpp;
• como aplic.cpp carrega pilha.h "para dentro" de si mesmo,
carregará 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. Módulo: lista.cpp
#include <stdio.h>
#include <stdlib.h>
#include “lista.h”
Lista::Lista() {
max = 30;
ultimo = -1;
}
Lista::~Lista() {
// Libera memória ocupada pelos Strings.
delete[] elemento;
}
36. Exercício de Implementação 4
Implementação de um programa com número
variável de filas com vetores alocadas
dinamicamente usando classe lista com vetor.
Este trabalho é bem fácil porque você já implementou
praticamente tudo o que precisa. Só tem agora que modificar
um pouco a forma de gerenciar os seus dados.
Tome a classe Fila com Vetor que você já implementou e crie um
programa para gerenciar uma lista contendo um número
variável e menor do que 20 desses objetos. Cada Fila deverá
ter no máximo 20 posições.