Loading presentation...

Present Remotely

Send the link below via email or IM

Copy

Present to your audience

Start remote presentation

  • Invited audience members will follow you as you navigate and present
  • People invited to a presentation do not need a Prezi account
  • This link expires 10 minutes after you close the presentation
  • A maximum of 30 users can follow your presentation
  • Learn more about this feature in our knowledge base article

Do you really want to delete this prezi?

Neither you, nor the coeditors you shared it with will be able to recover it again.

DeleteCancel

Make your likes visible on Facebook?

Connect your Facebook account to Prezi and let your likes appear on your timeline.
You can change this under Settings & Account at any time.

No, thanks

Algoritmos Computacionais

Ponteiros
by

Onezimo Cardoso

on 25 November 2014

Comments (0)

Please log in to add your comment.

Report abuse

Transcript of Algoritmos Computacionais

Algoritmos Computacionais
Ponteiros
Prof. Onézimo Cardoso
Objetivos
Introdução dos conceitos básicos;
Noção de variável, endereço e ponteiro;
Operadores * (apontado por) e & (endereço);
Noção de NULL;
Declaração e carga inicial de variáveis do tipo ponteiro;
Aritmética de ponteiros;
Passagem de vetores para funções;
Ponteiros de ponteiros;
Ponteiros
Um ponteiro é uma variável que aponta sempre para outra variável de um determinado tipo;

Para indicar que uma variável é do tipo ponteiro, coloca-se um asterisco antes dela;
Conceitos Básicos
Todo programa que roda em um computador, passa pela memória RAM;

Nela são carregados nossos jogos, processadores de texto, etc;

É também na RAM que são armazenadas as variáveis que fazem parte dos nossos programas;
De fato, a memória RAM pode ser vista como um enorme vetor de bytes consecutivos:




Cada um desses bytes ocupa uma posição bem determinada em memória, que é identificada por um número único que varia entre 0 e a totalidade de bytes que ocupam a memória RAM do computador;
Sempre que declaramos uma variável, temos que indicar qual o seu tipo e qual o seu nome:

char ch;




A variável ch ocupa, no exemplo acima o byte de memória de número 5000;
É mais simples referenciar uma variável pelo seu nome do que referenciá-la pela posição que ela ocupa na memória;

Quando fazemos

ch = 'A';

Estamos informando ao computador para ir à posição 5000 de memória e colocar lá o caractere 'A';

É o compilador que realiza essa conversão por nós;

Apenas temos que nos preocupar em escrever o programa corretamente;
O compilador associa a cada variável uma posição ÚNICA em memória, capaz de suportar os dados do tipo dessa variável;

Sempre que num programa se faz referência a uma variável estamos, na realidade, nos referindo ao endereço ou conjunto de endereços que essa variável ocupa;
Suponhamos que tenhamos um ponteiro denominado ptr;

Como qualquer variável, ptr ocupa uma posição em memória;

Pelo fato de ptr ser ponteiro, por isso deverá conter o endereço de memória de outra variável;

Note que o endereço de uma variável é o número da casa que esta ocupa na memória;

Por isso, para colocarmos ptr apontando para a variável ch bastará colocar o endereço de ch em ptr;

Isso se faz utilizando o operador & (Endereço de):

ptr = &ch;

O objetivo de um ponteiro é armazenar o endereço de outra variável, o qual é, por sua vez, um número;

Se uma variável do tipo ponteiro é capaz de armazenar um número (o endereço de outra variável), então terá que ocupar espaço na memória;

Devemos então declarada tal como qualquer outra variável:

tipo * ptr;

ptr - É o nome da variável do tipo ponteiro;

tipo - É o tipo da variável para a qual apontará;

* - Indica que é uma variável do tipo ponteiro;

A declaração de ponteiros pode ser realizada no meio de outras variáveis do mesmo tipo;




O asterisco utilizado na declaração de ponteiros é o mesmo que é usado para a operação de multiplicação, no entanto não provoca qualquer confusão, pois o seu significado depende do contexo em que é usado;
As três declarações seguintes são equivalentes:
Embora as três declarações sejam equivalentes:



Podemos nos enganar pensando que x,y,z são variáveis do tipo int*, isto é, que todas elas são ponteiros;

Na verdade, apenas a variável x é do tipo int*, sendo todas as outras, inteiros perfeitamente banais;
Carga Inicial Automática de Ponteiros
A carga inicial de ponteiros se faz através do operador Endereço de - &;

Tal operador pode também ser utilizado para iniciar uma variável do tipo ponteiro no momento de sua declaração;
Podem existir situações em que declaramos um ponteiro e não queremos que ele aponte para variável alguma;

Nesse caso, posso colocá-lo apontando para NULL;


Ponteiros em Ação
Uma vez declarado um ponteiro, podem ser realizados sobre ele praticamente todos os tipos de operações que podemos realizar sobre inteiros;

No entanto, um ponteiro serve, sobretudo, para permitir acessar outros objetos através dos seus endereços;






Para colocar ptr apontando para a faz-se:

ptr = &a;
Após a instrução anterior o valor de:





O valor da variável cujo endereço está armazenado em ptr é acessado por * ptr (APONTADO POR ptr);

Dessa forma, fazer

printf("%d",a);

É equivalente a

printf("%d",*ptr);

Pois ptr aponta para a e *ptr corresponde ao valor de a;
Qual a saída do programa abaixo?


No programa anterior, se adicionássemos *ptr=20, alteraríamos automaticamente o valor de a que é apontado por ptr;

Repare que se quiséssemos declarar outro ponteiro p2 e apontarmos para a, poderiámos fazer:

p2 = &a;

p2 = ptr /* Sem endereço, pois ptr já contém o endereço de a;
No exemplo a seguir:





Teríamos
Nos exemplos anteriores vimos as variáveis ocupando apenas um byte de memória, de forma a facilitar a apresentação do assunto;

Na realidade, os tipos de dados em C (char, int, float, double) ocupam diferentes números de bytes em memória, podendo, inclusive, o mesmo tipo ocupar um número diferente de bytes em diferentes arquiteturas, como é o caso do inteiro (dois ou quatro bytes);
Quando declaramos as seguintes variáveis:

char a= 'Z';
int n= 1234;
float pi = 3.1415;

Estamos indicando ao compilador qual o espaço que ele deverá reservar para cada uma dessas variáveis:






O espaço de armazenamento de um caractere não é o mesmo que para um inteiro ou para um real;
Implemente uma função que forneça a quantidade de bytes ocupados por variáveis char, int, float e double
Exemplo
O nome de um vetor corresponde ao endereço de seu primeiro elemento:

v==&v[0]

Isto é, o nome de um vetor é um ponteiro para o primeiro elemento desse vetor;
Ponteiros e Vetores
Dados:

int v[3]={10,20,30};
int *ptr;

Existem duas formas de colocar ptr apontando para o primeiro elemento de v:

1. ptr=&v[0];
2. ptr=v;
Os elementos de um vetor ocupam posições consecutivas de memória, sendo o nome do vetor igual ao endereço do primeiro elemento;

Isto é, o menor endereço do vetor;
Observação
Sendo os ponteiros números que representam posições de memória, podem ser realizadas algumas operações aritméticas (incremento, decremento, diferença e comparação) sobre eles;
Aritmética de Ponteiros
Um ponteiro pode ser incrementado como qualquer outra variável;

No entanto, o incremento de uma unidade não significa que o endereço anteriormente armazenado no ponteiro seja incrementado em um byte;

Incremento de Ponteiro
Na realidade, se ptr é um ponteiro para um determinado tipo, quando ptr é incrementado, por exemplo, em uma unidade, o endereço que passa a conter é de:

ptr+sizeof(tipo)

Onde "tipo" representa o tipo da variável para qual o ponteiro aponta;

Portanto, o ponteiro não incrementa um byte, mas sim a dimensão do tipo de objeto para o qual aponta;
Portanto, o ponteiro não incrementa um byte, mas sim a dimensão do tipo de objeto para o qual aponta;
Exemplo
Na operação de incremento, podem-se utilizar os operadores normais:
Observação
O decremento de ponteiros funciona da mesma forma que o incremento anteriormente apresentado;

Decremento de Ponteiro
Exemplo
Escreva um programa que mostre uma string na tela pela ordem em que está escrita e pela ordem contrária;

A operação de diferença entre dois ponteiros para elementos do mesmo tipo, permite determinar quantos elementos existem entre um endereço e outro;

Por exemplo, o comprimento de uma string pode ser obtido através da diferença entre o endereço do caractere '\0' e o endereço do caractere original;

É importante ressaltar que a diferença entre ponteiros só pode ser realizada entre ponteiros do mesmo tipo;

Diferença de Ponteiros
Exemplo
Implemente uma função que calcule o tamanho de uma string fornecida pelo usuário do programa;

É também possível realizar a comparação de dois ponteiros do mesmo tipo;

Tal como fizemos pa parte final do Algoritmo para escrever a string na ordem contrária;

Para realizarmos a comparação, utilizamos operadores relacionais (<,<=,>,>=,==,!=);

Comparação de Ponteiros
Suponhamos a seguinte declaração:



Como poderemos acessar o caractere 'a' presente na string?
Ponteiros e Vetores - Acesso aos elementos
Se
vetor
for um vetor já declardo, então:

Sempre que invocamos uma função e lhe passamos um vetor como parâmetro, esta na realidade não recebe um vetor na sua totalidade, mas apenas o endereço inicial do vetor, pois estamos passando
s==&s[0]
;





Se passarmos um endereço, então a variável que o recebe terá que ser um ponteiro para o tipo dos elementos do vetor;

Por essa razão é que no cabeçalho de uma função que recebe um vetor como argumento aparece normalmente um ponteiro recebendo o respectivo parâmetro;
Vejamos agora como poderíamos ter implementado a função de cópia de string, utilizando ponteiro;







Note que a função recebe o endereço das duas strings, copiando em seguida o caractere da string
orig
para string
dest
;








Depois de copiados todos os caracteres de
orig
, (incluindo o delimitador) é necessário retornar o endereço inicial da string de destino;

No entando, esse endereço já foi perdido pelo fato de dest ter avançado ao longo das posições da string;

Para resolver esse problema, antes de alterar o ponteiro
dest
coloca-se o seu valor numa variável temporária (char *tmp = dest);
Vamos agora implementar a função que junta (concatena) a string orig à string dest;

Nesse caso, o objetivo é copiar a string orig para o final da string dest:







Uma vez que queremos copiar uma string para o final da outra, enviamos os endereços de início da string
orig
e o endereço do '\0' da string dest para que a cópia seja realizada a partir desses endereços e não a partir dos endereços de ambas as strings;

Depois de terminada a função strcpy, bastará retornar dest, isto é, o endereço inicial da string destino;
Uma vez que os ponteiros ocupam espaço em memória, é possível obter a sua posição através do operador endereço &;
Ponteiros de Ponteiros
Se estivermos interessados em armazenar o endereço de um ponteiro, qual o tipo de variável que irá recebê-lo?
Suponhamos uma variável do tipo int chamada x:


Se pretendemos armazenar seu endereço, declaramos um ponteiro para o tipo da variável (int), isto é, colocamos um asterisco entre o tipo da variável para que queremos apontar e o nome do ponteiro:
Agora, se quisermos armazenar o endereço desse ponteiro, seguimos exatamente os mesmos passos, declarando uma variável do tipo do ponteiro ptr_x (int *) e colocando um asterisco entre o tipo da variável para a qual queremos apontar e o nome do ponteiro;
No exemplo seguinte os três
printf
colocam a mesma informação na tela:
Como se pode ver, ptr_x aponta para a variável x, enquanto ptr_ptr_x aponta para ptr_x:
Full transcript