Buscar

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 3, do total de 45 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 6, do total de 45 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 9, do total de 45 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Continue navegando


Prévia do material em texto

Ju
d
so
n
 S
an
to
s 
S
an
ti
ag
o
PONTEIROS
Alocação Dinâmica de Memória
Introdução
 Para armazenar dados no computador um 
programa gerencia:
 Onde a informação esta armazenada
 Que tipo de informação é armazenada 
 Que valor é mantido lá
00001100
00110110 Endereços de Memória
3126
(short)
0xCB20
0xCB21
0xCB22
0xCB23
0xCB24
0xCB25
Introdução
 A declaração de uma variável num programa 
realiza estes passos necessários para o 
armazenamento de dados
short total; // declaração de variável
total = 3126; // atribuição de valor
00001100
00110110
3126 = total
0xCB20
0xCB21
0xCB22
0xCB23
0xCB24
0xCB25
= total
0xCB20
0xCB21
0xCB22
0xCB23
0xCB24
0xCB25
short
Declaração Atribuição
Endereços de Variáveis
 Todo nome de variável esta associado a um 
endereço na memória
 O operador de endereço & pode ser usado 
para obter a localização de uma variável
short total; // declaração de variável
total = 3126; // atribuição de valor
cout << total; // valor da variável
cout << &total; // endereço da variável
Endereços de Variáveis
#include <iostream>
using namespace std;
int main()
{
int copos = 6;
double cafe = 4.5;
cout << "Valor de copos = " << copos << endl;
cout << "Endereço de copos = " << &copos << endl;
cout << "Valor de cafe = " << cafe << endl;
cout << "Endereço de cafe = " << &cafe << endl;
system("pause");
return 0;
}
Endereços de Variáveis
 Saída do programa:
 Execução 1
 Execução 2
Valor de copos = 6
Endereço de copos = 0027FCF8
Valor de cafe = 4.5
Endereço de cafe = 0027FCE8
Valor de copos = 6
Endereço de copos = 0021F8FC
Valor de cafe = 4.5
Endereço de cafe = 0021F8EC
Ponteiros
 Existe outra estratégia para armazenar dados 
no computador: 
 Alocar memória manualmente
 Guardar o endereço de memória em um ponteiro
 Usar o ponteiro para acessar e modificar os dados
 Para usar esta estratégia é necessário o 
conhecimento de ponteiros
Ponteiros
 Um ponteiro é um tipo especial que guarda 
valores que são endereços de memória
 Da mesma forma que uma variável char tem 
um caractere como valor e um int tem um 
número como valor
2.6
0x27FCF8
120
G ch
num
ptr
mult
0x27FCF8
0x27FCF9
0x27FCFD
0x27FD01
char ch = 'G';
int num = 120;
float mult = 2.6;
char * ptr = (char *) 0x27FCF8;
0x27FD05
0x27FD09
Ponteiros
 A declaração de um ponteiro segue o 
seguinte padrão:
char * ptr;
O tipo do elemento apontado Nome do ponteiro
Operador de indireção
Ponteiros
 Como o ponteiro contém um endereço de 
memória, diz-se que ele aponta para aquela 
posição de memória
2.6
0x27FCF8
120
G ch
num
ptr
mult
0x27FCF8
0x27FCF9
0x27FCFD
0x27FD01
0x27FD05
0x27FD09
char ch = 'G';
int num = 120;
float mult = 2.6;
char * ptr = (char *) 0x27FCF8;
Ponteiros
 O nome de um ponteiro 
representa uma localização 
na memória
 O operador de indireção * pode ser usado 
para obter o valor armazenado na memória
// declaração do ponteiro
char * ptr = (char *) 0x27FCF8;
cout << ptr; // endereço armazenado
cout << *ptr; // valor apontado
2.6
0x27FCF8
120
G ch
num
ptr
mult
0x27FCF8
0x27FCF9
0x27FCFD
0x27FD01
0x27FD05
0x27FD09
Ponteiros
#include <iostream>
using namespace std;
int main()
{
int total = 6; // declara uma variável
int * pt; // declara um ponteiro
pt = &total; // atribui endereço de total
cout << "Valor de total = " << total << endl;
cout << "Valor de pt = " << *pt << endl;
cout << "Endereço de total = " << &total << endl;
cout << "Endereço de pt = " << pt << endl;
*pt = *pt + 1; // altera valor
cout << "Agora total vale = " << total << endl;
system("pause");
return 0;
}
Ponteiros
 Saída do Programa:
 A alteração de *pt mudou o valor da variável 
apontada pelo ponteiro
Valor de total = 6
Valor de pt = 6
Endereço de total = 0034FBBC
Endereço de pt = 0034FBBC
Agora total vale = 7
*pt = *pt + 1; // altera valor
cout << "Agora total vale = " << total << endl;
Variável versus Ponteiro
 Ao usar uma variável:
 O valor é um elemento que possui um nome
 A localização do valor é um elemento derivado (&)
 Ao usar um ponteiro:
 A localização é um elemento que possui um nome
 O valor é um elemento derivado (*)
int * pt = &total; // pt se refere ao endereço
cout << *pt; // *pt se refere ao valor
int total = 6; // total se refere ao valor
cout << &total; // &total se refere ao endereço
Declaração de Ponteiros
 Por que não se declara um ponteiro da 
mesma forma que um int, char ou float?
 Não é suficiente dizer que uma variável é um 
ponteiro, é preciso também especificar para 
que tipo de dado ele aponta
char ch = 'G';
int num = 120;
float f = 2.1;
char * pc = &ch;
int * pi = &num;
float * pf = &f;
pointer p = &ch;
// cout não sabe o tipo de *p
cout << *p;
Declaração de Ponteiros
 Na declaração de um ponteiro o uso de 
espaços ao redor do (*) é opcional
 Cuidado com declarações múltiplas
int *ptr; // enfatiza que *ptr é um int
int* ptr; // enfatiza que ptr é um ponteiro para int 
int * ptr; // estilo neutro
// p1 é um ponteiro para int, p2 é um int 
int * p1, p2;
// p1 e p2 são ponteiros para int 
int *p1, *p2; 
Cuidado com Ponteiros
 Ao declarar um ponteiro o computador não 
aloca automaticamente memória para 
guardar o valor apontado
long * ptr; 
*ptr = 504;
ptr 0x27FCF8
504
ptr
long val; 
long * ptr = &val;
*ptr = 504;
val0x27FCF8
0x27FCF9
0x27FCFD
0x27FD01
0x27FD05
0x27FD09
0x27FCF8
0x27FCF9
0x27FCFD
0x27FD01
0x27FD05
0x27FD09
Atribuição de Valores
 Endereços de memória não são valores do 
tipo inteiro:
 Um endereço tem 4 bytes
 Um inteiro pode ter 2 bytes (antigo MS-DOS)
 É possível converter um inteiro para um 
endereço de memória usando um type cast
int * p = 0x27FCF8; // inválido, mistura de tipos
int * p = 0xB80000; // inválido, mistura de tipos
int * p = (int *) 0x27FCF8; 
int * p = (int *) 0xB80000; 
Atribuição de Valores
 O type cast converte para um endereço e 
indica também o tipo do valor apontado
 Ao usar o operador & o tipo do endereço já 
está definido pelo tipo da variável
char * p = (char *) 0x27FCF8; // endereço de um char
char ch = 'G';
char * p = &ch; // endereço de um char
Alocação de Memória
 Ponteiros tem sido usados para guardar 
endereços de variáveis já existentes
 Variáveis são memórias rotuladas durante o 
processo de compilação
 Neste caso os ponteiros fornecem apenas uma 
segunda forma de acesso as variáveis
 O verdadeiro poder dos ponteiros está em 
apontar para memória não rotulada, alocada
durante a execução do programa
Alocação de Memória
 A alocação de memória é feita com o 
operador new
int * pn = new int;
Operador new
retorna o endereço 
da memória alocada
Tipo de dado
Ponteiro compatível com o 
tipo de dado requisitado
Alocação de Memória
#include <iostream>
using namespace std;
int main()
{
int * pi = new int; // aloca memória para um inteiro
*pi = 1001; // guarda um valor lá
cout << "Valor inteiro = " << *pi << endl;
cout << "Localização = " << pi << endl << endl;
double * pd = new double; // aloca memória para um double
*pd = 500.35; // guarda um valor lá
cout << "Valor ponto-flutuante = " << *pd << endl;
cout << "Localização = " << pd << endl << endl;
cout << "Tamanho de pi = " << sizeof(pi) << endl;
cout << "Tamanho de *pi = " << sizeof(*pi)<< endl << endl;
cout << "Tamanho de pd = " << sizeof(pd) << endl;
cout << "Tamanho de *pd = " << sizeof(*pd) << endl;
system("pause");
return 0;
}
Alocação de Memória
 Saída do programa:
Valor inteiro = 1001
Localização = 00114CD0
Valor ponto-flutuante = 500.35
Localização = 00114DA8
Tamanho de pi = 4
Tamanho de *pi = 4
Tamanho de pd = 4
Tamanho de *pd = 8
Liberando Memória
 Toda memória alocada com new deve ser 
liberada ao final do seu uso
 O operador delete permite retornar a 
memória não mais usada para uso do 
sistema, ou de novas alocações
int * ps = new int; // aloca memória com new 
... // usa memória
delete ps; // libera memória ao final
Liberando Memória
 O operador delete libera a memória mas não 
destrói o ponteiro
 O mesmo ponteiro pode ser usado para receber 
outro endereço de memória
int * ps = new int; // aloca memória com new 
*ps = 30; 
cout << *ps;
delete ps; // libera memória ao final
ps = new int; // aloca nova memória
*ps = 50;
cout << *ps;
delete ps; // libera nova memória
Liberando Memória
 Um uso de new deve ser sempre balanceado
com um uso de delete
 Caso contrário tem-se um memory leak
int * ps = new int; // aloca memória com new 
*ps = 30; 
cout << *ps;
ps = new int; // memory leak
*ps = 50; 
cout << *ps;
delete ps; // libera última alocação
Liberando Memória
 Não se pode liberar o mesmo bloco de 
memória duas vezes
int * ps = new int; // aloca memória com new 
*ps = 30; 
cout << *ps;
...
delete ps; // libera memória ao final
delete ps; // resultado indefinido
Liberando Memória
 Não se pode usar delete para liberar memória 
criada com a declaração de variáveis
int val; // declaração de variável 
val = 30; 
cout << val;
...
delete val; // inválido, não foi alocado com new
Vetores Dinâmicos
 Um vetor criado por uma declaração de 
variável é chamado de vetor estático
 É preciso definir previamente o tamanho 
do vetor em tempo de compilação
 Usando new é possível criar um vetor com 
tamanho definido durante a execução do 
programa
int vet[10]; // vetor de 10 inteiros 
Vetores Dinâmicos
 Para criar um vetor dinâmico com new basta 
passar o tipo e o número de elementos
 O ponteiro recebe o endereço do primeiro 
elemento do vetor 
int * vet = new int [20];
Operador new
Tipo de dado
Ponteiro compatível com o 
tipo de dado requisitado
Quantidade de elementos
Vetores Dinâmicos
 Para liberar a memória de um vetor dinâmico 
é preciso usar delete com uma notação 
especial
delete [] vet;
Operador delete Endereço da memória alocada
Memória contém um vetor
Vetores Dinâmicos
 O ponteiro de um vetor dinâmico pode ser 
usado como se fosse um vetor
5
15
0x27FD09
0x27FD0D
30 0x27FD11
28 0x27FD15
pvet
int * pvet = new int [5];
pvet[0] = 15;
pvet[1] = 5;
pvet[2] = 30;
pvet[3] = 28;
pvet[4] = 40;
cout << pvet[0]; // 15
cout << *pvet; // 15
40 0x27FD19
0x27FD1D
0x27FD01
0x27FD05
0x27FD09
Vetores Dinâmicos
#include <iostream>
using namespace std;
int main()
{
double * p3 = new double [3]; // memória para três doubles
p3[0] = 0.2;
p3[1] = 0.5;
p3[2] = 0.8;
cout << "p3[1] = " << p3[1] << endl;
p3 = p3 + 1; // incrementa o ponteiro
cout << "Agora p3[0] = " << p3[0] << endl;
cout << "Agora p3[1] = " << p3[1] << endl;
p3 = p3 - 1; // retorna ao inicio
delete [] p3; // libera a memória
system("pause");
return 0;
}
Vetores Dinâmicos
 Saída do programa:
 Um ponteiro é uma variável e seu conteúdo 
pode ser modificado através de uma 
atribuição
p3[1] = 0.5
Agora p3[0] = 0.5
Agora p3[1] = 0.8
p3 = p3 + 1; // incrementa o ponteiro
p3 = p3 - 1; // decrementa o ponteiro
Vetores Dinâmicos
 Um ponteiro pode ser usado como um vetor
 Um vetor pode ser usado como um ponteiro
int * pvet = new int [10];
pvet[0] = 15;
pvet[1] = pvet[0] + 5;
cout << pvet[1];
int vet[10];
*vet = 15; // vet[0] = 15;
*(vet + 1) = *vet + 5; // vet[1] = vet[0] + 5;
cout << *(vet + 1); // cout << vet[1];
Vetores Dinâmicos
 Um vetor estático é um ponteiro constante 
para o primeiro elemento do vetor
5
15
0x27FD09
0x27FD0D
30 0x27FD11
28 0x27FD15
vet
int vet[5];
vet[0] = 15;
vet[1] = 5;
vet[2] = 30;
*(vet+3) = 28;
*(vet+4) = 40;
cout << vet[1]; // 5
cout << *(vet+1); // 5
vet = vet + 1; // inválido
40 0x27FD19
0x27FD1D
0x27FD01
0x27FD05
0x27FD09
Registros Dinâmicos
 O operador new também pode ser usado 
para criar registros dinâmicos
jogador * pj = new jogador;
Operador new
Tipo de dado
Ponteiro compatível com o 
tipo de dado requisitado
struct jogador
{
char nome[40];
float salario;
unsigned gols;
};
Registros Dinâmicos
 O operador membro (.) não pode ser usado
com um registro dinâmico
 C++ oferece o operador (->) para acessar 
membros de um registro dinâmico
 Usa-se (.) com variáveis tipo registro
 Usa-se (->) com ponteiros para registros
jogador * pj = new jogador;
cout << pj->nome; 
cout << pj->salario; 
cout << pj->altura; 
Registros Dinâmicos
#include <iostream>
using namespace std;
struct jogador
{
char nome[40];
float salario;
unsigned gols;
};
int main()
{
jogador * pbeb = new jogador; 
strcpy(pbeb->nome, "Bebeto");
pbeb->salario = 200000;
pbeb->gols = 600;
cout << "Contratação para o próximo ano:\n" 
<< pbeb->nome << " por " << pbeb->salario << " Reais\n";
delete pbeb;
system("pause");
return 0;
}
Registros Dinâmicos
 Saída do programa:
 Atribuição a um registro dinâmico:
Contratação para o próximo ano:
Bebeto por 200000 Reais
jogador * prom = new jogador;
strcpy(prom->nome, "Romario");
prom->salario = 300000;
prom->gols = 800;
Vetores Dinâmicos
 O operador new também pode ser usado 
para criar vetores dinâmicos de registros
jogador * pt = new jogador [22];
Operador new
Tipo de dado
Ponteiro compatível com o 
tipo de dado requisitado
struct jogador
{
char nome[40];
float salario;
unsigned gols;
};
Quantidade de elementos
Vetores Dinâmicos
 O operador (.) deve ser usado com a notação 
de vetor
 O operador (->) deve ser usado com a 
notação de ponteiro
cout << pt->nome; // nome do primeiro jogador
cout << (pt+1)->salario; // salario do segundo jogador
cout << (pt+21)->altura; // altura do ultimo jogador
cout << pt[0].nome; // nome do primeiro jogador
cout << pt[1].salario; // salario do segundo jogador
cout << pt[21].altura; // altura do ultimo jogador
Vetores Dinâmicos
#include <iostream>
using namespace std;
struct jogador
{
char nome[40];
float salario;
unsigned gols;
};
int main()
{
jogador * ptime = new jogador[22];
cout << "Digite o nome, salario e gols de dois jogadores: ";
cin >> ptime[0].nome; cin >> ptime[0].salario; cin >> ptime[0].gols;
cin >> ptime[1].nome; cin >> ptime[1].salario; cin >> ptime[1].gols;
cout << "\nCusto da aquisição: R$"
<< ptime[0].salario + ptime[1].salario << "!\n";
delete [] ptime;
system("pause");
return 0;
}
Vetores Dinâmicos
 Saída do programa:
Digite o nome, salário e gols de dois jogadores:
Bebeto 200000 600
Romario 300000 800
Custo da aquisição: R$500000!
Conclusão
 Ponteiros são variáveis que armazenam 
endereços de memória
 A sua principal função é guardar o endereço 
de memória alocada dinamicamente com o 
operador new
 Permite alocar variáveis durante a execução
 Permite criar vetores dinâmicos
 Permite criar registrosdinâmicos