ponteiros - dc.ufscar.br€¦ · ponteiros! usado para criar e manipular estrutura de dados que...
TRANSCRIPT
Programação de Computadores 185
Ponteiros! Usado para criar e manipular estrutura de dados que
podem aumentar/diminuir de tamanho como listas encadeadas, árvores, etc.
! Conceitos Básicos:! ponteiro=> variável que armazena um endereço de
memória.! variável=> contem um valor! ponteiro=> contem o endereço de uma variável que por
sua vez armazena um valor! variável=> diretamente referencia um valor! ponteiro=> indiretamente referencia um valor
Programação de Computadores 186
! Como as variáveis, os ponteiros devem ser declarados antes do seu uso:int *ptcont, cont; nessa declaração temos:
" ptcont-> ponteiro para uma posição de memória que armazena um inteiro. Em outras palavras, o conteúdo da posição de memória chamada ptcont, é o endereço de uma posição de memória que armazena um inteiro.
" cont -> posição de memória que armazena um inteiroint *pty, *ptx;
" duas posições de memória que armazenam um endereço de memória onde será armazenado um inteiro.
Programação de Computadores 187
! ponteiros podem ser iniciados quando declarados ou por uma comando de atribuição. Valores possíveis:0, NULL ou um endereço. (NULL é uma constante simbólica definida em iostream.h)
NULL e 0 são equivalentes-> 0 é mais usado.! Operadores:
! & -> operador unário de endereço. Quando aplicado retorna o endereço do operando.Exemplo:int y = 5;int *pty;pty = &y;
atribui a pty o endereço da variável y ...
pty
5y
...
Programação de Computadores 188
// usando os operadores & e *#include <iostream.h>void main( ){ int a;
int *ponta; // ponta é um ponteiro para uma posição de memória // que armazena um inteiro
a = 7;ponta = &a;cout<<“Endereço de memória onde está armazenada a variável a:”
<<&a<<endl<<“Valor de ponta é:"<<ponta<<endl<<endl<<"O valor da variável a é:"<<a<<endl<<"O valor de *ponta é:"<<*ponta<<endl<<endl<<“* e & são complementares um do outro"<<endl <<"&*ponta="<<&*ponta<<endl<<"*&ponta=“<<*&ponta<<endl;
}
Programação de Computadores 189
Endereço de memória onde está armazenado a variável a:0x603f293aValor de ponta é:0x603f293a
O valor da variável a é:7O valor de *ponta é:7
* e & são complementares um do outro&*ponta =0x603f293a*&ponta =0x603f293a
Programação de Computadores 190
! Arranjo de Ponteiros! int a[10]; declara um arranjo de 10 posições! se não conhecemos antecipadamente o tamanho do problema,
podemos deixar que o usuário indique o tamanho desejado na hora da execução.
#include <iostream.h>#include <assert.h>void main( ){ int *arranjo, tamanho;cout<<"entre com o tamanho do arranjo:"; cin>>tamanho;arranjo = new int[tamanho];assert(arranjo!=0);cout<<endl<<"entre agora com os elementos do arranjo:";for (int i=0; i<tamanho;i++) cin>>arranjo[i];cout<<endl<<"Arranjo montado:"<<endl;for (int i=0;i<tamanho;i++) cout<<" "<<arranjo[i];
}
Programação de Computadores 191
#include <assert.h>void assert(int test);Descrição: Testa uma condição e aborta a execução se o teste falhar. É uma macro. Quando falha, além de abortar o programa emite uma mensagem indicando o teste que falhou, o nome do arquivo onde foi feito o teste e o número da linha dentro do arquivo
Programação de Computadores 192
! Podemos fazer a mesma alocação para matrizes.float **matriz;int nro_linhas, nro_colunas;cout<<"Entre com o nro de linhas da matriz:";cin>>nro_linhas;matriz= new float* [nro_linhas];assert(matriz!=0);cout<<"Entre agora com o nro de colunas da matriz:";cin>>nro_colunas;for (int i=0;i<nro_linhas;i++){ matriz[i]= new float[nro_colunas];
assert(matriz[i]!=0);}
Programação de Computadores 193
! matriz= new float* [nro_linhas];! se nro_linhas =3
for (int i=0; i<nro_linhas;i++)matriz[i]=new float [nro_colunas]; //se nro_colunas=3
matriz 012
matriz
0
1
2
0 1 2
Programação de Computadores 194
! Matriz Triangular15712
02915
0 00 03 0
21 4
0
321
01
23
≠0 só os elementos que tem i ≤ jfloat **matriang;int ordem;cin>>ordem;matriang = new float*[ordem]; assert(matriang!=0);for (int i=0; i<ordem;i++){ matriang[i] = new float [i+1];
assert(matriang[i]!=0);}
Programação de Computadores 195
! Fazer a alocação para matriz triangular superior.! char *cad[4]={“ouro”, “copas”, “paus”, “espada”};
O
C O
UAP
cad[0]0 1 2 3
cad[3]cad[2]cad[1]
U R O \0
4
AP S \0
S \0
\0ADAPSE
5 6
TAMANHOS DIFERENTES PARA AS COLUNAS
Programação de Computadores 196
! Simulando embaralhar e distribuir cartas=> baralho tem 52 cartas, 13 cartas de cada naipe. Podemos imaginar o baralho como sendo um arranjo de 4 linhas correspondendo aos naipes e 13 colunas correspondendo a numeração das cartas.
copas0 1 2 3
espadapausouro
4 12111098765
AS 2 3 4 5 6 7 8 9 10 rei
dama
valete
0
1
2
3
cartas
cartas[2][12] representa o Rei de paus
Programação de Computadores 197
! A simulação do embaralhamento das cartas pode ser feita usando o seguinte método. ! O arranjo cartas é iniciado com 0. ! Aleatoriamente é escolhida uma linha(0-3) e uma coluna(0-12)! O número 1 é inserido na posição cartas[linha][coluna] para
indicar que na distribuição essa será a primeira carta. ! O mesmo processo é feito com os números 2,3,4,…, 52. Se uma
posição selecionada já tiver aparecido em outra rodada, ela é ignorada e outra linha e coluna é selecionada.
! Quando todo o arranjo tiver sido preenchido, as cartas serão distribuídas.
PS: Um programa escrito usando esse algoritmo pode rodar indefinidamente. Pq?
Programação de Computadores 198
! Depois de embaralhado, quando formos proceder a distribuição temos que ter uma forma de “traduzir” cartas[linha] [coluna] para o texto equivalente ao significado da carta. Por exemplo, se cartas[2][12]=1 temos que distribuir a carta Rei de Ouro.
! Uma maneira simples é criar um arranjo de ponteiros para caracteres naipe[4], colocando na posição naipe[0]= ‘copas’, naipe[1]=‘ouro’, naipe[2]=‘paus’ e naipe[3]=‘espada’. Uma vez determinada a linha, basta ir no arranjo naipe na linha selecionada e imprimir o conteúdo.
! O mesmo pode ser feito com o valor das cartas. Criamos um arranjo de ponteiros para caracteres valor[13], sendo que valor[0]=‘As’, valor[1]=‘dois’,…, valor[10]=‘Valete’, valor[11]=‘Dama’ e valor[12]=‘Rei’.
Programação de Computadores 199
! Vamos usar a metodologia de desenvolvimento chamada de refinamentos sucessivos.
! Embaralhe e distribua as 52 cartas! inicie o arranjo cartas! inicie o arranjo valor! inicie o arranjo naipe! embaralhe as cartas! distribua as cartas
! Embaralhe as cartas pode ser expandida para:! para cada uma das 52 cartas
faça { linha#número aleatório entre 0 e 4 ;coluna#número aleatório entre 0 e 12;enquanto cartas[linha][coluna] ≠0faça { linha#número aleatório entre 0 e 4 ;
coluna#número aleatório entre 0 e 12;}
carta[linha][coluna]# número da carta}
Programação de Computadores 200
! Distribua as cartaspara cada uma das 52 cartasfaça { procura pela posição cartas[linha][coluna]=valor
da carta;imprime valor[coluna] seguido da cadeia “de”
seguido de naipe[linha];}
Programação de Computadores 201
#include <iostream.h>#include <iomanip.h>#include <stdlib.h>#include <time.h>void embaralha(int[][13]);void distribui(int[][13], char*[ ], char*[ ]) ;void main( ){ char *naipe[]={"copas","ouro","paus","espada"};
char *valor[ ]={"As","dois","tres","quatro","cinco","seis","sete","oito","nove","dez","valete","dama","rei"};
int cartas[4][13]={0};srand(time(NULL));embaralha(cartas);distribui(cartas,valor,naipe);
}
Programação de Computadores 202
void embaralha(int baralho[ ][13]){ int linha,coluna;
for (int carta=1;carta<=52;carta++){ linha = rand()% 4; coluna = rand( ) % 13;while (baralho[linha][coluna]!=0){ linha = rand( ) % 4; coluna = rand( ) % 13;}
baralho[linha][coluna] = carta ;}
}void distribui(int baralho[ ][13], char* face[ ], char *naipe[ ]){ for (int carta = 1; carta<=52; carta++)
for (int linha=0; linha<=3; linha++)for (int coluna=0; coluna<=12; coluna++)if (baralho[linha][coluna] == carta)cout<<setw(5)<<setiosflags(ios::right)<<face[coluna]
<<" de "<<setw(8)<<setiosflags(ios::left)<<naipe[linha]<< (carta%3==0?'\n':'\t');
}
Programação de Computadores 203
! Ponteiro para funções=> contem o endereço da função na memória.
! Vimos que o nome de um arranjo é também o endereço na memória do primeiro elemento do arranjo
! Nome de uma função => é o endereço onde inicia o código que realiza as tarefas da função.
! Ponteiro para função:! podem ser passados para outras funções! pode ser retornado de uma função! armazenado em arranjos! atribuído a outros ponteiros para funções.
Programação de Computadores 204
#include <iostream.h>#include <iomanip.h>void ordena(int [ ], const int, int(*)(int,int));int ascendente(const int,const int);int descendente(const int, const int);void main( ){ const int tamanho=10;
int ordem,cont, a[tamanho]={2,6,4,8,10,12,89,68,45,37};cout<<"Entre com o valor 1 se a ordenação for crescente"<<endl
<<"Entre com o valor 2 para ordenação decrescente"<<endl;cin>>ordem;cout<<endl<<"Dados na ordem original"<<endl;for (cont=0;cont<tamanho;cont++) cout<<setw(4)<<a[cont];if (ordem==1){ ordena(a, tamanho,ascendente);cout<<endl<<"Elementos em ordem crescente"<<endl;
}else{ ordena(a, tamanho, descendente);cout<<endl<<"elementos em ordem decrescente"<<endl;
}for (cont=0;cont<tamanho;cont++) cout<<setw(4)<<a[cont];cout<<endl;
}
Programação de Computadores 205
void ordena(int a[ ], const int tam, int(*compare)(int,int)){ int aux; ;
int posicao;for (int i=0; i<tam-1; i++){ aux = a[i]; posicao = i;for (int j=i+1; j<tam;j++)if ((*compare)(aux,a[j])){ aux= a[j]; posicao =j;}
if (posicao!= i){ a[posicao] = a[i]; a[i] = aux;}
}}
int ascendente(const int a, const int b){ return b<a;}
int descendente(const int a, const int b){ return b>a;}
Programação de Computadores 206
! Funções: ordena, ascendente e descendente! ordena=> recebe um ponteiro para uma função que pode
ser ascendente ou descendente, junto com o arranjo e seu tamanho.
! Programa pergunta ao usuário o tipo de ordenação desejado. Se for ascendente (tipo 1) o ponteiro para a função ascendente é passado para a função ordena.
! int(*) (int,int) => diz para a função ordena esperar 1 parâmetro que é 1 ponteiro para uma função que tem como parâmetro dois inteiros.
! No programa o código (if (*compare)(aux,a[j])) é equivalente a if (compare(aux,a[j]). PQ?
! Nome da função é um ponteiro para a mesma
Programação de Computadores 207
! Maior uso de ponteiros para função: Sistemas orientados a menu.
! Usuário seleciona um opção a partir de um menu. Cada opção é executada por uma função diferente.
! Os ponteiros para cada função são armazenados num arranjo de ponteiros para função. A escolha do usuário é usada como índice para o arranjo e o ponteiro armazenado na posição usado para chamar a função correspondente.
Programação de Computadores 208
#include <iostream.h>void funcao1(int);void funcao2(int);void funcao3(int);void main( ){ void (*f[3])(int)={funcao1,funcao2,funcao3};
int escolha;cout<<"Entre com o valor entre 1 e 3, 0 para terminar:";cin>>escolha;while (escolha>=1 && escolha<=3){ f[escolha-1](escolha); // seleciona o ponteiro na posição
//escolhida do arranjocout<<"Entre com um valor entre 1 e 3, 0 para terminar:";cin>>escolha;
}cout<<"Você entrou com o valor 0, portanto encerrando o
programa"<<endl;}
f é um arranjo de 3 posição sendo que cada uma delas é um ponteiro para uma função que recebe como argumento um inteiro e retorna void. O arranjo é iniciado com o nome da função correspondente
Programação de Computadores 209
void funcao1(int a){ cout<<"Você entrou com o valor "<<a<<" então a
função 1 foi chamada"<<endl<<endl;}
void funcao2(int a){ cout<<"Você entrou com o valor "<<a<<" então a
função 2 foi chamada"<<endl<<endl;}
void funcao3(int a){ cout<<"Você entrou com o valor "<<a<<" então a
função 3 foi chamada"<<endl<<endl;}