You are on page 1of 35

Universidade do Amazonas

Departamento de Ciência da Computação


Especialização em Desenvolvimento de Sistemas

Estruturas de Dados e Algoritmos


Alocação Dinâmica de Memória

Rosiane de Freitas Rodrigues, Profa. M.Sc.


rosiane@dcc.fua.br
http://www.dcc.fua.br/~rosiane

setembro de 2001
Manaus - AM
Alocação de Memória
PROBLEMA

O que fazer quando o número de elementos e sua forma de


organização variam dinamicamente?

Para resolver este problema é necessário um mecanismo que permita:

 Criar espaço para novas variáveis em tempo de execução;

 Definir “ligações” entre tais variáveis, dinamicamente, de tal forma a


relacioná-las.
Alocação de Memória

– Num vetor, tanto o número como a forma de


organização são fixos.

– Em Pascal ou C, o tipo file define uma estrutura que


possui um número indeterminado de elementos,
porém sempre organizados em seqüência na
memória.
Alocação de Memória

SOLUÇÃO

Utilização de ALOCAÇÃO DINÂMICA DE MEMÓRIA, o que


significa definir e manipular variáveis especiais denominadas
PONTEIROS ou APONTADORES.
Alocação de Memória
PONTEIRO é ...

– uma variável especial que contém o endereço de


memória de outra variável (variável dinâmica);

– variável que contém endereços de posições de


memória alocadas na memória.

VARIÁVEL VARIÁVEL
PONTEIRO DINÂMICA

endereço de conteúdo do tipo


memória da T que se deseja
variável “acessar”
dinâmica
Alocação de Memória

VARIÁVEL VARIÁVEL
PONTEIRO DINÂMICA

endereço de conteúdo do tipo


memória da T que se deseja
variável “acessar”
dinâmica

ptr <sem nome>

1237 5

1237
Alocação de Memória

 as variáveis dinâmicas não podem ser referenciadas


diretamente, por isto não possuem nome próprio;

 o acesso ao conteúdo de uma variável dinâmica é obtido


através de ponteiros;

 a variável ponteiro, apesar de conter um endereço de


memória qualquer (o qual é um inteiro), deve ser declarado
como sendo do mesmo tipo de dado que está contido na
variável dinâmica;

- pode ter um ponteiro para qualquer tipo de variável.


Alocação de Memória

 uma implementação ligada (por contigüidade lógica


ou por alocação dinâmica) utiliza apontadores (do
inglês pointers);

 Os ponteiros podem substituir matrizes estáticas com


mais eficiência. Também fornecem a maneira pelas
quais procedimentos e funções possam modificar os
argumentos chamados.
Alocação de Memória
Alocação Dinâmica
 Consiste na alocação de porções de memória durante a
execução do programa.

 A alocação é feita em uma região especial do espaço de


endereçamento do programa chamada HEAP;

 O heap, ao contrário dos registros de ativação da stack, é


visível em qualquer ambiente do programa em execução, ou
seja, embora a alocação seja feita durante a ativação de um
determinado bloco do programa, ela continua a existir após o
término da execução de tal bloco.
Alocação de Memória
Alocação Dinâmica

 Variáveis dinâmicas não têm nome (identificadores)


associados a elas;

 A referência a cada uma delas é feita através de seu


endereço na área de heap, ou seja, de um ponteiro para
a variável.
Alocação de Memória
Alocação Dinâmica em C
PONTEIROS EM C

 O grande potencial e flexibilidade da Linguagem C é devido ao uso de


ponteiros;

 Pode-se ter um ponteiro para qualquer tipo de variável. C usa


ponteiros explicitamente em matrizes, estruturas e funções.

 O operador unário & indica o endereço de uma variável.

 O operador de indireção * indica o conteúdo de um objeto


apontado por um ponteiro.
Alocação de Memória
Alocação Dinâmica em C
DECLARAÇÃO

<Tipo T> *<nome-do-ponteiro> /* Ponteiro para um


valor do tipo T*/

O conteúdo do ponteiro pode consistir de:

– um número de endereços, cada qual identificando uma


variável do tipo T;

– mais o valor especial NULL, que não identifica qualquer


variável.
Alocação de Memória
Alocação Dinâmica
PROCEDIMENTOS BÁSICOS

Dois procedimentos pré-definidos, em várias linguagens, são utilizados para


alocar e desalocar variáveis na área de heap:

ALOCAR
DESALOCAR
ALOCAR (ptr)

Aloca uma variável dinâmica de tipo T e atribui o seu endereço ao


parâmetro ptr;
DESALOCAR (ptr)

Desaloca uma variável dinâmica de tipo T, cujo endereço é dado


pelo parâmetro ptr, ficando este indefinido.
Alocação de Memória
Alocação Dinâmica em C
DECLARAÇÃO

int *pint ; pint

PROCEDIMENTOS BÁSICOS

ALOCAR - MALLOC
pint = (int *) malloc (sizeof (int)); // Cria a var dinâmica *pint pint 340 *pint
DESALOCAR - FREE 340

free (pint); pint


Alocação de Memória
Alocação Dinâmica em C
pint := NULL;
símbolo usado para representar o
NULL - ponteiro para ninguém

pint = (T *) malloc ( sizeof (T) )


pint *pint

o valor de pint variável dinâmica do tipo T


é o endereço (denota-se por *pint)
Alocação de Memória

CONSIDERAÇÕES SOBRE LIBERAÇÃO DE MEMÓRIA


– Em MODULA-3 e JAVA, que possui coletor automático de
lixo, o procedimento DISPOSE não é necessário.
– Em C e PASCAL, é necessário explicitar a alocação e a
desalocação de ponteiros.

INTERESSANTE
– Em JAVA, a alocação dinâmica de memória é realizada
implicitamente pela linguagem.
» Criar um OBJETO, significa ALOCAR uma porção de
MEMÓRIA DINAMICAMENTE.
Alocação de Memória
Alocação Dinâmica em C
DECLARAÇÕES

Declarando um ponteiro p/ um inteiro e uma variável x inteira:


int x, *ptr_x;

Para o ponteiro apontar para x, ou seja, guardar o endereço de x, tem-se:


ptr_x = &x; /* a variável ptr_x aponta para x */

Para o acesso ao conteúdo da variável para qual o ponteiro aponta, tem-


se:
y = *ptr_x; /* o que é a mesma coisa que: y=x; */
Alocação de Memória
Alocação Dinâmica em C

IMPORTANTE:

– Um ponteiro é associado a um tipo


determinado. Não se pode atribuir o endereço
de um short int para um long int, por exemplo.
Alocação de Memória
Alocação Dinâmica em C

OPERAÇÕES C/ PONTEIROS

– Atribuição de endereços ao ponteiro;

– Obtenção de acesso à variável dinâmica referenciada pelo


apontador (esta operação é conhecida por
derreferenciação);

– Soma e subtração de ponteiro (deslocamento de posição na


memória);

– Comparação entre ponteiros com os operadores de igualdade


e desigualdade.
Alocação de Memória
Alocação Dinâmica em C
MANIPULAÇÃO DE PONTEIROS

Considere o efeito do seguinte código:

int x=1, y=2;


int *ptr;
ptr = &x;
y = *ptr;
x = ptr;
*ptr = 3;

Assuma que a variável x reside na posição de memória 100, que y reside na


posição 200 e ptr, na posição 1000.
Alocação de Memória
Alocação Dinâmica em C
Então: x y ptr
int x=1, y=2;
1 2 lixo
int *ptr;
100 200 1000

ptr = &x; 1 2 100

100 200 1000

y = *ptr; 1 1 100

100 200 1000


Alocação de Memória
Alocação Dinâmica em C
x y ptr

y = *ptr; 1 1 100

100 200 1000

x = ptr; 100 1 100

100 200 1000

*ptr = 3; 3 1 100

100 200 1000


Alocação de Memória
Alocação Dinâmica em C
IMPORTANTE
Em alguns compiladores C, quando um ponteiro é declarado
automaticamente é alocado um endereço válido de memória a ele.

Entretanto, sempre que possível, um bom código deve suportar qquer


ambiente e compilador. Neste caso, tal alocação deve ser feita pelo programa:
Então:
int *ptr; ptr
*ptr = 100;
lixo
Isto gerará um erro. O correto seria:
int *ptr;
int x;
ptr x
ptr = &x;
*ptr = 100; 320 100

40 320
Alocação de Memória
Alocação Dinâmica em C
IMPORTANTE
– Um ponteiro para qualquer tipo é um endereço na memória - que
geralmente é um endereço inteiro.
– A razão para que seja associado um ponteiro para um tipo de dado é para
saber com quantos bytes será necessário para o dado ser armazenado.
Quando se incrementa o ponteiro, na verdade, se incrementa o ponteiro por
um “bloco de memória”.

Desta forma:
 Uma operação de soma num ponteiro do tipo char - ++ch_ptr adiciona 1
byte para o endereço;
 Uma operação de soma num ponteiro do tipo inteiro ou float - ++int_ptr ou
++fl_ptr adiciona 2 bytes e 4 bytes para o endereço, respectivamente.
Alocação de Memória
Alocação Dinâmica em C
IMPORTANTE
Considere uma variável float (fl) e um ponteiro para um float (fl_ptr):

1 float (4 bytes)

fl
flp ++flp flp+2

– No exemplo acima, assumindo o ponteiro flp para fl, quando se incrementa


o ponteiro (++flp) ele é deslocado para a posição 4 bytes adiante.
– Se, por outro lado, se incrementa o ponteiro de float com 2, então ele é
deslocado 2 posições float, ou seja, 8 bytes.
Alocação de Memória
Alocação Dinâmica em C
EXEMPLO

main()
{ int x, y, *px, *py;
x = 34; y=10;
px=&x;
py=px;
printf(“x=%d\n”,x);
printf(“&x=%d\n”,&x);
printf(“px=%d\n”,px);
printf(“*px=%d\n”,*px);
printf(“y=%d\n”,y);
printf(“&y=%d\n”,&y);
printf(“py=%d\n”,py);
printf(“*py=%d\n”,*py); }
Alocação de Memória
Alocação Dinâmica em C
PONTEIRO PARA PONTEIRO
– Um ponteiro para um ponteiro é uma forma de indicação múltipla.
– Num ponteiro normal, o valor do ponteiro é o valor do endereço da variável que
contém o valor desejado.
– Neste caso, o primeiro ponteiro contém o endereço do segundo, que aponta para a
variável que contém o valor desejado.

float **balanco; /*balanco é um ponteiro para float*/


Por exemplo:
main()
{ int x, *p, **q;
x = 10;
p=&x;
q=&p;
printf(“%d”,**q); }
Alocação de Memória
Alocação Dinâmica em C
Verifique os seguintes comandos:

int *p, *q;


int x;
p = (int *) malloc (sizeof (int) );
*p = 3;
q = p;
printf (“%d %d\n”, *p, *q);
x = 7;
*q = x;
printf (“%d %d\n”, *p, *q);
p = (int *) malloc (sizeof (int) );
*p = 5;
printf (“%d %d\n”, *p, *q);
Alocação de Memória
Alocação Dinâmica em C
PROBLEMA COM PONTEIROS

p = (int *) malloc (sizeof (int) );


*p = 5;
free(p);
p = (int *) malloc (sizeof (int) );
*p = 10;

– a primeira cópia de *p é perdida porque seu endereço não foi salvo;


– o espaço alocado para variáveis dinâmicas só podem ser acessados através de
um ponteiro;
– neste caso, a 1a. variável dinâmica não pode nem mesmo ter o espaço liberado.
SOLUÇÃO
– definir p como NULL após executar free(p).
Alocação de Memória
Alocação Dinâmica em C
PERIGO COM PONTEIROS

– se q e p são ponteiros com o mesmo valor, as variáveis dinâmicas *q e


*p são idênticas (referem-se ao mesmo objeto);
– neste caso, uma atribuição a *p muda o valor de *q.
– O programador é responsável pelo rastreamento de “quais ponteiros
estão apontando para aonde” e pelo reconhecimento da ocorrência de
tais resultados implícitos.
Alocação de Memória
Alocação Dinâmica
EXERCÍCIO 1 (em C):

Somar dois inteiros usando variáveis dinâmicas:


Alocação de Memória
EXEMPLO 1: Alocação Dinâmica em C
Somar dois inteiros usando variáveis dinâmicas (EM C):

TYPE Tptr = ^INTEGER;


Tptr *pint1, *pint2;
...
pint1 = (int *) malloc (sizeof (int) );
pint2 = (int *) malloc (sizeof (int) );
scanf (“%d %d\n”, pint1, pint2);
* pint1 : = * pint1 + * pint2;
printf (“%d %d\n”, *pint2, *pint2);
free (pint1);
free (pint2);
...
LISTAS LIGADAS

A estrutura de dados mais simples que pode ser obtida ligando


elementos com ponteiros é a LISTA:

 Cada elemento de uma LISTA LIGADA ou ENCADEADA é


representado separadamente;
 Todos os elementos são ligados através do uso de PONTEIROS.
LISTAS LIGADAS

PONTEIROS

É simplesmente uma variável cujo valor é o endereço de outro elemento.

LISTA LIGADA
É uma lista de pares, cada um consistindo de um elemento e um ponteiro, tal
que cada ponteiro contém o endereço do próximo par:
 Cada par é representado por um REGISTRO;
 A lista ligada pode ser percorrida seguindo os endereços dos ponteiros -
busca linear:
Não é possível o acesso direto a cada elemento da lista ligada.
LISTAS LIGADAS

DESVANTAGENS

 Existe um ponteiro (espaço de memória adicional) por elemento;


 Para visitar, por exemplo, o 30o elemento da lista, devem ser percorridos os 29
elementos anteriores.

Como detectar o final da lista?

Usando um endereço especial, chamado NIL, que é uma referência para ninguém.

You might also like