Algoritmos e Estruturas de Dados I Ponteiros Profa

  • Slides: 49
Download presentation
Algoritmos e Estruturas de Dados I – Ponteiros Profa. Mercedes Gonzales Márquez

Algoritmos e Estruturas de Dados I – Ponteiros Profa. Mercedes Gonzales Márquez

Variáveis (relembrando) l l Variável é um nome amigável (simbólico) que damos para uma

Variáveis (relembrando) l l Variável é um nome amigável (simbólico) que damos para uma localização de memória que receberá um dado de algum tipo. No momento da declaração de uma variável, um espaço de memória é alocado para ela. Nome (rótulo) Variável: Valor (conteúdo) inteiro: p, q, s real: r p ← 50 r ← 40. 5 Endereço na memória Conteúdo Nome p r s 1001 50 1005 40. 5 1009 q 2047

Ponteiros - Conceito l Um ponteiro é uma variável que armazena um endereço de

Ponteiros - Conceito l Um ponteiro é uma variável que armazena um endereço de memória. inteiro: p, r, *q real: r p ← 50 r ← 40. 5 q ←&p l O símbolo * indica que q é um ponteiro. Endereço na memória Conteúdo Nome p r s q 1001 50 1005 40. 5 1009 2047 1001 O nome ponteiro refere ao fato deste tipo especial de variável “apontar” para um endereço. O símbolo & representa o endereço.

Ponteiros - Declaração l l Ponteiro tem um tipo associado que determina o tipo

Ponteiros - Declaração l l Ponteiro tem um tipo associado que determina o tipo da dado contido no endereço apontado. Pode ser um tipo pré-definido da linguagem ou um tipo definido pelo programador. Exemplo: inteiro, literal, real, Tipo. Produto, etc. A declaração de um tipo ponteiro se faz com a seguinte sintaxe: tipo da dado apontado: *ponteiro Exemplos: Real: *p 1 Inteiro: *p 2 Literal: *p 3

Operadores indireção e endereço l l O símbolo * é chamado operador de indireção.

Operadores indireção e endereço l l O símbolo * é chamado operador de indireção. Se aplicado a um ponteiro, ele indica o valor armazenado no endereço contido no ponteiro. O símbolo & é conhecido como operador endereço. Anexado no início de um nome de variável, ele representa o endereço na memória onde o valor da Endereço na variável está armazenado. inteiro: cont ← 10, x, *p p ← &cont x ← *p escreva (cont, x); memória cont 1001 p 1005 x Conteúdo 10 1001 2047 10

Ponteiros – Operador & l Considere as declarações e inicializações inteiro: x, y, *p

Ponteiros – Operador & l Considere as declarações e inicializações inteiro: x, y, *p 1, *p 2 x ← -42 y ← 163 l Essas declarações alocam memória para duas variáveis do tipo inteiro e duas do tipo ponteiro a inteiro. Os seus valores serão armazenados nos endereços de memória indicados no seguinte diagrama.

Ponteiros – Operador & l Se fizermos: p 1 ← &x p 2 ←

Ponteiros – Operador & l Se fizermos: p 1 ← &x p 2 ← &y Teremos a memória no seguinte estado. antes depois lp 1 e p 2 apontam as variáveis que estão referenciando.

Ponteiros – Operador * l Se fizermos: *p 1 ← 17 muda o valor

Ponteiros – Operador * l Se fizermos: *p 1 ← 17 muda o valor na variável x devido que é onde p 1 aponta. Assim, teremos a seguinte configuração.

Ponteiros – Atribuindo outro ponteiro l Também é possível atribuir novos valores aos ponteiros.

Ponteiros – Atribuindo outro ponteiro l Também é possível atribuir novos valores aos ponteiros. Por exemplo p 1 ← p 2 leva ao computador a tomar o valor contido na variável p 2 (1004) e copiá-lo na variável p 1. Ao copiar este valor em p 1, ambos p 1 e p 2 apontarão à variável y, como mostramos no diagrama: 1004

Ponteiros – Atribuindo valores l Resumindo, nós podemos atribuir valores para um ponteiro de

Ponteiros – Atribuindo valores l Resumindo, nós podemos atribuir valores para um ponteiro de duas formas: – Usando o operador endereço Usando diretamente atribuição entre ponteiros. – l int *p; int x; p = &x; *p = 4; int *p; int *p 1; int x; p 1 = &x; p = p 1; *p = 4; Em ambos os casos estamos referenciando alguma variável.

Ponteiros – Apontando para lixo l Observe o seguinte exemplo: l O ponteiro p

Ponteiros – Apontando para lixo l Observe o seguinte exemplo: l O ponteiro p foi declarado, mas não lhe foi atribuído nenhum valor, ou seja p aponta a um endereço desconhecido (comumente chamado lixo). Quando o valor 4 é armazenado na localização que p aponta, nós não podemos saber onde o valor 4 será armazenado. l l int *p; *p = 4; Tentar acessar este valor pode gerar um erro fatal no nosso programa ou até sistema operacional.

Ponteiros – Constante NULO l Os valores de um ponteiro: – Um ponteiro a

Ponteiros – Constante NULO l Os valores de um ponteiro: – Um ponteiro a alguma outra variável. – Pode ser atribuído uma constante NULO Um ponteiro nulo não aponta a posição alguma. l É uma boa prática testar se o ponteiro é nulo antes de indagar sobre o valor apontado. inteiro: *ip ← NULO; se (ip <>NULO) escreva (*ip) l Se (ip ) escreva(*ip) l

Ponteiros e arrays l Nome de array é um apontador – int a[6]; int

Ponteiros e arrays l Nome de array é um apontador – int a[6]; int a 2[6]; l Passagem de array como parâmetro é por referência – funcao(int a[]) ou funcao(int *a)// declaração – funcao(a); // chamada l Operador atribuição não funciona – a ← a 2; // errado! Não é possível copiar diretamente l Identificador do array é o endereço 1º elemento – a é &a[0] l Conteúdo do array – Conteúdo da 1ª posição: *a ou a[0] – Conteúdo da 2ª posição: *(a+1) ou a[1]

Ponteiros e arrays • Assuma que Inteiro: *pa pa ← &a[0] ou pa←a •

Ponteiros e arrays • Assuma que Inteiro: *pa pa ← &a[0] ou pa←a • Então p aponta para a[0], *(pa+1) refere ao conteúdo de a[1], pa+i é o endereço de a[i] e *(pa+i) é o conteúdo de a[i]. • O valor em a[i] pode também ser escrito como *(a+i). O endereço &a[i] e a+i são também idénticos.

Ponteiros e arrays • Os elementos de um array podem ser acessados através de

Ponteiros e arrays • Os elementos de um array podem ser acessados através de índices como de ponteiros. Exemplo: vazio print 1(inteiro: vet[], inteiro: n) inteiro: i Para i de 1 até n repita escreva (vet[i]) vazio print 2(inteiro: vet[], int n) inteiro: * ptr Para ptr de vet até vet+n repita escreva (*ptr) vazio print 3(inteiro: *vet, inteiro: n) Inteiro: * ptr Para ptr de vet até vet+n repita escreva (*ptr); } vazio print 4(inteiro: *vet, inteiro: n) Inteiro: i Para i de 1 até n repita escreva (*vet) vet<-v+1

Alocação estática l l Até agora, todas as estruturas tinham tamanho prédefinido, exemplo matrizes

Alocação estática l l Até agora, todas as estruturas tinham tamanho prédefinido, exemplo matrizes e vetores. Esta alocação estática pode implicar em: – – desperdício dos recursos pois podemos definirmos um tamanho muito maior que aquele que normalmente será usado em tempo de execução. Pode-se, em contraste, subestimar o tamanho necessário para armazenar os dados.

Alocação dinâmica Na alocação dinâmica os espaços são alocados durante a execução do programa,

Alocação dinâmica Na alocação dinâmica os espaços são alocados durante a execução do programa, conforme este necessitar de memória. Não há reserva antecipada de espaço. Alocar memória dinamicamente significa gerenciar memória (isto é, reservar, utilizar e liberar espaço) durante o tempo de execução.

Ponteiros – Alocação dinâmica l l l Alocando espaço na Heap O uso mais

Ponteiros – Alocação dinâmica l l l Alocando espaço na Heap O uso mais importante de ponteiros é para apoio à alocação dinâmica, isto é, ao invés de apontar variáveis já alocadas do espaço de dados, utilizar o espaço de heap para novas variáveis, que podem ser liberadas após o uso, mesmo antes do término do programa. Para isso, é necessária uma operação de alocação de memória, e uma para liberação de memória.

Ponteiros – Alocação dinâmica l l A operação que aloca memória é implementada por

Ponteiros – Alocação dinâmica l l A operação que aloca memória é implementada por uma função, na forma: aloque(p) Esta operação reserva, na Heap, espaço suficiente para armazenar um dado do tipo apontado por p. Em p é armazenado o endereço de memória deste dado. A operação que libera memória é implementada por uma função, na forma: libere(p) Esta operação ‘retorna’ para a Heap aquele espaço ocupado pelo dado apontado por p, e anula p.

Ponteiros ou Apontadores Após a alocação o ponteiro passará apontar para uma área definida

Ponteiros ou Apontadores Após a alocação o ponteiro passará apontar para uma área definida da memória capaz de armazenar uma variável de determinado tipo. Exemplo: real: *p 1 inteiro: *p 2 literal: *p 3 aloque(p 1) aloque (p 2) aloque (p 3)

Ponteiros ou Apontadores Exemplo 1: inteiro: *p 2 aloque(p 2) *p 2 ←‘ a’

Ponteiros ou Apontadores Exemplo 1: inteiro: *p 2 aloque(p 2) *p 2 ←‘ a’ (errado) *p 2 ← 5 (certo)

Ponteiros ou Apontadores Exemplo 2: inteiro: *p 2 ← 5 (erro, o ponteiro não

Ponteiros ou Apontadores Exemplo 2: inteiro: *p 2 ← 5 (erro, o ponteiro não foi alocado) No seguinte exemplo atribuimos o valor nulo para um ponteiro, a fim de indicar que ainda não foi alocado espaço para ele. real: *ap 1 ←NULO

Ponteiros ou Apontadores Exemplo 3: inteiro: *p 2 aloque (p 2) *p 2 ←

Ponteiros ou Apontadores Exemplo 3: inteiro: *p 2 aloque (p 2) *p 2 ← 5 libere (p 2)

Ponteiros ou Apontadores l Exemplo 4: Inteiro: x, *p, *q x ← 1 p

Ponteiros ou Apontadores l Exemplo 4: Inteiro: x, *p, *q x ← 1 p ← &x *q ← 3 q ← p *q ← *p + 1 escreva(*p) l Teste de mesa inicial p x lixo q lixo

Ponteiros ou Apontadores l Exemplo 4: Inteiro: x, *p, *q x ← 1 p

Ponteiros ou Apontadores l Exemplo 4: Inteiro: x, *p, *q x ← 1 p ← &x *q ← 3 q ← p *q ← *p + 1 escreva(*p) p lixo q lixo x 1

Ponteiros ou Apontadores l Exemplo 4: Inteiro: x, *p, *q x ← 1 p

Ponteiros ou Apontadores l Exemplo 4: Inteiro: x, *p, *q x ← 1 p ← &x *q ← 3 q ← p *q ← *p + 1 escreva(*p) p x 1 q lixo

Ponteiros ou Apontadores l Exemplo 4: Inteiro: x, *p, *q x ← 1 p

Ponteiros ou Apontadores l Exemplo 4: Inteiro: x, *p, *q x ← 1 p ← &x *q ← 3 q ← p *q ← *p + 1 escreva(*p) p x 1 q lixo ERRO, q aponta para lixo

Ponteiros ou Apontadores l Exemplo 4: Inteiro: x, *p, *q x ← 1 p

Ponteiros ou Apontadores l Exemplo 4: Inteiro: x, *p, *q x ← 1 p ← &x *q ← 3 q ← p *q ← *p + 1 escreva(*p) p x 1 q

Ponteiros ou Apontadores l Exemplo 4: Inteiro: x, *p, *q x ← 1 p

Ponteiros ou Apontadores l Exemplo 4: Inteiro: x, *p, *q x ← 1 p ← &x *q ← 3 q ← p *q ← *p + 1 escreva(*p) p x 2 q

Ponteiros ou Apontadores l Exemplo 4: Inteiro: x, *p, *q x ← 1 p

Ponteiros ou Apontadores l Exemplo 4: Inteiro: x, *p, *q x ← 1 p ← &x *q ← 3 q ← p *q ← *p + 1 escreva(*p) p x 2 q Resultado = 2

Ponteiros ou Apontadores Exemplo 4: Alocação dinâmica Inteiro: *p, *q aloque(p) *p ← 1

Ponteiros ou Apontadores Exemplo 4: Alocação dinâmica Inteiro: *p, *q aloque(p) *p ← 1 q ← p *q ← *p + 1 escreva(*p) libere(p) l l Teste de mesa inicial p lixo q lixo

Ponteiros ou Apontadores Exemplo 4: Alocação dinâmica Inteiro: *p, *q aloque(p) *p ← 1

Ponteiros ou Apontadores Exemplo 4: Alocação dinâmica Inteiro: *p, *q aloque(p) *p ← 1 q ← p *q ← *p + 1 escreva(*p) libere(p) l lixo q

Ponteiros ou Apontadores Exemplo 4: Alocação dinâmica Inteiro: *p, *q aloque(p) *p ← 1

Ponteiros ou Apontadores Exemplo 4: Alocação dinâmica Inteiro: *p, *q aloque(p) *p ← 1 q ← p *q ← *p + 1 escreva(*p) libere(p) l lixo q

Ponteiros ou Apontadores Exemplo 4: Alocação dinâmica Inteiro: *p, *q aloque(p) *p ← 1

Ponteiros ou Apontadores Exemplo 4: Alocação dinâmica Inteiro: *p, *q aloque(p) *p ← 1 q ← p *q ← *p + 1 escreva(*p) libere(p) l p 1 q lixo

Ponteiros ou Apontadores Exemplo 4: Alocação dinâmica Inteiro: *p, *q aloque(p) *p ← 1

Ponteiros ou Apontadores Exemplo 4: Alocação dinâmica Inteiro: *p, *q aloque(p) *p ← 1 q ← p *q ← *p + 1 escreva(*p) libere(p) l p 1 q

Ponteiros ou Apontadores Exemplo 4: Alocação dinâmica Inteiro: *p, *q aloque(p) *p ← 1

Ponteiros ou Apontadores Exemplo 4: Alocação dinâmica Inteiro: *p, *q aloque(p) *p ← 1 q ← p *q ← *p + 1 escreva(*p) libere(p) l p 2 q

Ponteiros ou Apontadores Exemplo 4: Alocação dinâmica Inteiro: *p, *q aloque(p) *p ← 1

Ponteiros ou Apontadores Exemplo 4: Alocação dinâmica Inteiro: *p, *q aloque(p) *p ← 1 q ← p *q ← *p + 1 escreva(*p) libere(p) l p 2 q Resultado = 2

Ponteiros ou Apontadores Exemplo 4: Alocação dinâmica Inteiro: *p, *q aloque(p) *p ← 1

Ponteiros ou Apontadores Exemplo 4: Alocação dinâmica Inteiro: *p, *q aloque(p) *p ← 1 q ← p *q ← *p + 1 escreva(*p) libere(p) l

Ponteiros ou Apontadores Exemplo 4: Alocação dinâmica Inteiro: *p, *q aloque(p) *p ← 1

Ponteiros ou Apontadores Exemplo 4: Alocação dinâmica Inteiro: *p, *q aloque(p) *p ← 1 q ← p *q ← *p + 1 escreva(*p) libere(p) l Para evitar accidentes acrescente: q ← nulo p ← nulo

Ponteiros ou Apontadores Exemplo 5: Tipo reg: registro real: valor reg: *pont Fim_Registro reg:

Ponteiros ou Apontadores Exemplo 5: Tipo reg: registro real: valor reg: *pont Fim_Registro reg: *p, *q, x, x 1 x. valor ← 10. 5 p ←&x x. pont ←&x 1 l l Teste de mesa inicial p lixo q lixo

Ponteiros ou Apontadores Exemplo 5: Tipo reg: registro real: valor reg: *pont Fim_Registro reg:

Ponteiros ou Apontadores Exemplo 5: Tipo reg: registro real: valor reg: *pont Fim_Registro reg: *p, *q, x, x 1 x. valor ← 10. 5 p ←&x x. pont ←&x 1 l p lixo q lixo

Ponteiros ou Apontadores Exemplo 5: Tipo reg: registro real: valor reg: *pont Fim_Registro reg:

Ponteiros ou Apontadores Exemplo 5: Tipo reg: registro real: valor reg: *pont Fim_Registro reg: *p, *q, x, x 1 x. valor ← 10. 5 p ←&x x. pont ←&x 1 x 1. valor ← 0, 2 q ← x. pont x 1. pont ← NULO l p lixo Usamos o símbolo Para indicar que o ponteiro aponta para nulo

Ponteiros ou Apontadores p escreva(*p. valor) escreva(*q. valor) escreva(*p. *pont. valor) escreva(x 1. valor)

Ponteiros ou Apontadores p escreva(*p. valor) escreva(*q. valor) escreva(*p. *pont. valor) escreva(x 1. valor)

Ponteiros ou Apontadores p escreva(*p. valor) escreva(*q. valor) escreva(*p. *pont. valor) escreva(x 1. valor)

Ponteiros ou Apontadores p escreva(*p. valor) escreva(*q. valor) escreva(*p. *pont. valor) escreva(x 1. valor) 10, 5 0, 2

Ponteiros ou Apontadores Exercícios: (1) Qual é a saída de c em inteiro *p,

Ponteiros ou Apontadores Exercícios: (1) Qual é a saída de c em inteiro *p, *q, a, b, c a ← 1 b ← 2 p ← &a q ← &b c ← *p + *q

Ponteiros ou Apontadores Exercícios: (2) Qual é a saída de c em inteiro *p,

Ponteiros ou Apontadores Exercícios: (2) Qual é a saída de c em inteiro *p, **r, a, c, b a ← 1 b ← 2 p ← &a r ← &p c ← **r + b (3) Obtenha a saída do algoritmo anterior fazendo com que p e q sejam alocadas dinamicamente. Não use x nem x 1.

Ponteiros ou Apontadores Exercícios: (4) Por que o algoritmo abaixo está errado? procedimento troca

Ponteiros ou Apontadores Exercícios: (4) Por que o algoritmo abaixo está errado? procedimento troca (inteiro: *i, *j) inteiro *temp Início *temp ← *i *i ← *j *j ← *temp Fim

Ponteiros ou Apontadores (5) Dado o seguinte algoritmo, complete as Tabelas 1 e 2.

Ponteiros ou Apontadores (5) Dado o seguinte algoritmo, complete as Tabelas 1 e 2. inteiro: i, j, *p_1, *p_2, **p_p_1, **p_p_2 i ← 4 j ← 5 p_1 ← &i p_2 ← &j p_p_1 ← &p_2 p_p_2 ← &p_1

Ponteiros ou Apontadores l(6) Vamos criar os seguintes procedimentos: le. Coordenada 3 D(Coordenada 3

Ponteiros ou Apontadores l(6) Vamos criar os seguintes procedimentos: le. Coordenada 3 D(Coordenada 3 d *f); : lê dados de um ponto no espaço tridimensional com coordenadas (x, y, z) passada como ponteiro. (Por quê como ponteiro? ) l imprime. Coordenada 3 D(Coordenada 3 d f); Imprime coordenadas de um ponto no espaço tridimensional. l. O programa principal que requeira a leitura de 5 pontos no espaço tridimensional. (7) Refaça o exercício 6 considerando um vetor de pontos tridimensionais de tamanho dinâmico (use aloque). l