Post on 22-Apr-2015
Educação Profissional Técnica de Nível Médio
Curso Técnico de Informática
Disciplina: Estrutura de Dados Professor: Cheli dos S. Mendes da Costa
Ponteiros
Ponteiros
“Memória?”Uma memória é uma sequência de células de
armazenamento (ou posições)
Ponteiro
“Variável?”
“Uma variável é um aglomerado de uma ou mais células de memória”.
Variável Atributos de uma variável
– nome: sequência de caracteres utilizada para identificar a variável;
– tipo: é o tipo dos dados que serão armazenados na variável;
– conteúdo: é o valor armazenado na variável;
– endereço: é a localização (posição) da variável na memória;
Variável – char sexo = ‘M’;
• Nome da variável: sexo • Tipo da variável: char • Conteúdo da variável: ‘M’ • Endereço da variável: 5
Variável – int idade = 31;
• Nome da variável: idade • Tipo da variável: int • Conteúdo da variável: 31 • Endereço da variável: 1
Variáveis do tipo ponteiro
Ponteiros, como o próprio nome diz, é um tipo de variável que aponta para outra (de um tipo qualquer).
• Um ponteiro guarda o endereço de memória de uma variável.
• Sintaxe: Variáveis que são ponteiros são representadas da seguinte forma:
tipo_dado_apontado *nome_variavel;
– int *ptr1; – char *ptr2;
Variáveis do tipo ponteiro Utilizado para:
– Substituir a manipulação de vetores/matrizes com eficiência;
– Passar valores e mudar valores dentro de funções;
– Manipular arquivos;
– Aumento de eficiência para algumas rotinas;
– Possibilitar a alocação dinâmica de memória.
Variáveis do tipo ponteiro Operadores de Endereço &
– O (“endereço de”) antes de um nome de variável qualquer retorna o endereço desta variável.
– O (“conteúdo de”) antes de um nome de variável do tipo ponteiro retorna o conteúdo armazenado na posição de memória apontada. Operação chamada de indireção ou desreferenciamento.
Variáveis do tipo ponteiro char letra = ‘Z’; char *ptr = & letra;
– Nome da variável: ptr – Tipo da variável: char * – Conteúdo da variável: 1 – Endereço da variável: 4
Variáveis do tipo ponteiro void main(){ int x = 50; int * ptr;
printf (“%i”,x); /*exibe o conteúdo da variável x (50)*/ printf (“%p”,&x); /*exibe o endereço da variável x*/ ptr = &x; /*armazena em ptr o endereço de x*/ printf (“%p”,ptr); /*exibe o conteúdo da variável ptr*/ printf (“%p”,&ptr); /*exibe o endereço da variável ptr*/ printf (“%i”,*ptr); /*exibe o conteúdo da variável x*/
}
Variáveis do tipo ponteiro void main () { int x; int *ptr;
printf(“Digite um valor para x:”); scanf(“%i”, &x); ptr = &x; *ptr = *ptr + 1; printf(“O valor de x é %i”, *ptr); printf(“O endereço de x é %i”, ptr);
}
Variáveis do tipo ponteiro
*p ⇒ representa o conteúdo da variável apontada.
p ⇒ representa o endereço de memória da variável apontada.
Variáveis do tipo ponteiro Observação
– Quando queremos indicar que um ponteiro está “vazio”, ou seja, não contém um endereço de uma variável, atribuímos a ele o valor NULL.
•NULL: Endereço de memória 0 (zero). Esta posição de memória não é utilizada para armazenar dados.
• Exemplo: ptr = NULL; /* inicializa o ponteiro ptr*/
Variáveis do tipo ponteiro int a = 5, b = 7; (neste exemplo, um int ocupa 2bytes na memoria, e não 4, como em outros exemplos).
int *ptr = NULL;
Ptr = &a;
Variáveis do tipo ponteiro Atribuição
– Podemos atribuir o conteúdo de um ponteiro a outro. Dessa forma, teremos dois ponteiros referenciando o mesmo endereço de memória.
• Exemplo: int a = 5, *p1, *p2; p1 = &a; p2 = p1;
Aritmética de ponteiros Sendo os ponteiros números que representam posições de memória, podem ser realizadas algumas operações aritméticas sobre eles:
- Incremento; – Decremento; – Diferença; – Comparação.
Aritmética de ponteiros Incremento e Decremento
– Um ponteiro pode ser incrementado como qualquer outra variável
- Se ptr é um ponteiro para um determinado tipo, quando ptr é incrementado, por exemplo, de uma unidade, o endereço que passa a conter é igual ao endereço anterior de ptr + sizeof(tipo) para que o ponteiro aponta
– A mesma situação ocorre para a operação de decremento, onde o endereço que passa a conter é igual ao endereço anterior de ptr - sizeof(tipo) para que o ponteiro aponta.
Pesquisar
Aritmética de ponteiros
int main(int argc, char **argv) {
x = 5, *px = &x; double y = 5.0, *py = &y; printf("%i %i\n", x, px); printf("%i %i\n", x+1, px+1);
printf("%f %i\n", y, py); printf("%f %i\n", y+1, py+1);
printf("%i %i\n", x, px); printf("%i %i\n", x-1, px-1);
printf("%f %i\n", y, py); printf("%f %i\n", y-1, py-1); getchar(); return 0; }
Testar
Aritmética de ponteiros Além das operações de incremento e decremento, só é possível somar ou subtrair inteiros de um ponteiro:
– ptr = ptr + 7; • Esta expressão faz com que ptr aponte para o sétimo elemento a partir do seu elemento atual.
– ptr = ptr – 5; • Esta expressão faz com que ptr aponte para o quinto elemento anterior ao elemento atual.
Somar 2 a um ponteiro de inteiros de 4 bytes irá incrementá-lo em 8. Isso faz com que o incremento de um ponteiro o posicione para o próximo elemento em um arranjo, o que geralmente é o resultado intencionado.
Aritmética de ponteiros
Adição: somar um inteiro a um ponteiro
Fator de escala: é o tamanho (número de bytes) do objeto apontado.
Exemplo: fator de escala de uma variável do tipo float: 4 p = p + 2 significa p = p + 2 * fator de escala
Aritmética de ponteiros
Subtração: subtrair um inteiro de um ponteiro
p = p - 3 significa p = p - 3 * fator de escala
Aritmética de ponteiros
Incremento: somar um a um ponteiro
Aritmética de ponteiros
Decremento: subtrair um de um ponteiro
Aritmética de ponteiros Comparação
– É possível comparar dois ponteiros em uma expressão relacional.
-Exemplo: É possível verificar se um ponteiro aponta para um endereço menor que o endereço apontado por outro ponteiro:
if (px < py) printf(“px aponta para memória mais baixa que py”);
Aritmética de ponteiros Precedência de Operadores
– O operador * e & têm maior precedência que os operadores aritméticos, de forma que:
// obtém o valor do objeto apontador por px, adiciona 1 e
//atribui o valor a y y = *px + 1;
// y recebe o conteúdo do endereço de px+1 y = *(px + 1);
Expressões com ponteiros
– Os operadores ++ e -- possuem precedência sobre o * e operadores matemáticos
(*px)++; //soma 1 no conteúdo de px
*px++; //adianta uma posição de memória e obtém o seu //conteúdo
*(px--); //volta uma posição de memória e obtém //o seu conteúdo ⇒ o mesmo que *px—
Cuidado com ponteiros perdidos!
Aritmética de ponteiros Diferença – A operação de diferença entre elementos de mesmo tipo permite saber quantos elementos existem entre um endereço e outro.
– Exemplo:
#include <stdio.h> void main(){
int x = 5, *px = &x; int y = 10, *py = &y; printf("%i %d\n", x, px); printf("%i %d\n", y, py); printf("\A diferenca entre eles eh: %d", py - px); getchar(); }
Ponteiro para estrutura Como os outros tipos do C, as estruturas podem ser referenciadas usando ponteiros.
Ponteiro para estrutura
Há duas formas para recuperar os valores de uma estrutura usando o ponteiro:
– Se st é uma estrutura e ptr é um ponteiro para st, para referenciar a estrutura usamos:
(*ptr).elemento ou ptr->elemento
Ponteiro para estrutura
Testar
Ponteiro para estrutura
Testar
Exercício
Fazer um programa que permita a entrada de registros com nome, cidade e telefone de 1 pessoa usando a sintaxe de ponteiro para estrutura.
Ponteiro e Vetor O nome de um vetor corresponde ao endereço do seu primeiro elemento, isto é, se v for um vetor então v é igual ao &v[0].
Embora o nome de um vetor seja um ponteiro para o primeiro elemento do vetor, esse ponteiro não pode ser alterado durante a execução do programa a que pertence.
Ponteiro e Vetor Existem duas formas de colocar um ponteiro apontando para o primeiro elemento de um vetor:
int v[3] = {10, 20, 30}; int * ptr;
ptr = &v[0]; // ou ptr = v;
Ponteiro e Vetor Ao contrário de v, que é um vetor (ponteiro constante associado à sua própria memória), ptr é um ponteiro puro, e portanto pode receber endereços de diferentes elementos de um vetor.
int v[3] = {10, 20, 30}; int *ptr; ptr = v; printf(“%i %i”, v[0], *ptr); /* 10 10 */ ptr = &v[2] printf(“%i %i”, v[2], *ptr); /* 30 30 */
Ponteiro e Vetor Outra sintaxe – Colocamos em c o endereço do terceiro elemento de vetor: char vetor[5] = { ‘a’, ‘e’, ‘i’, ‘o’, ‘u’ };
char *c; c = &vetor[2];
– Portanto: c[0] = ‘i’; c[1] = ‘o’ e c[2] = ‘u’.
– Se tivéssemos feito c = &vetor[3], então: c[0] = ‘o’ e c[1] = ‘u’.
Ponteiro e Vetor Usando aritmética de ponteiros, como acessar os valores do vetor usando a variável ponteiro c ?
#include <stdio.h> void main(){ int i; char vetor[5] = { 'a', 'e', 'i', 'o', 'u' }; char *c; c = vetor; for (i = 0; i < 5; i++) { printf("\n%c ", c[i]); /* ou */ printf("%c ", *(c + i)); } getchar(); }
Ponteiro e Vetor Usando a sintaxe de ponteiro e de vetor de que forma poderemos acessar o caractere ‘a’ presente na string “OlaOleOli”?
#include <stdio.h> #include <stdio.h>
void main(){ int i; char vetor[] = "OlaOleOli"; char *c = vetor; printf("\n%c ", vetor[2]); Testar printf("%c ", *(c + 2)); printf("\n%c ", c[2]); printf("%c ", *(vetor + 2)); getchar(); }
Ponteiro e Vetor Resumo – Quando estamos manipulando ponteiros para vetores:
*c ⇒ representa o conteúdo da variável.
*(c + i) ⇒ representa o i-ésimo elemento do vetor referenciado pelo ponteiro.
c[i] ⇒ também representa o i-ésimo elemento do vetor referenciado pelo ponteiro.
c ⇒ representa o endereço de memória da variável.
Exercício – Dadas as variáveis float vet_notas[5] e float *pont_notas, imprimir a primeira e a quinta nota usando as duas variáveis.
printf(“A primeira nota: %i”, vet_notas[0]); printf(“A primeira nota: %i”, *pont_notas); printf(“A quinta nota: %i”, vet_notas[4]; printf(“A quinta nota: %i”, *(pont_notas+4));
Passagem de Vetores para funções
Sempre que invocamos uma função e lhe passamos um vetor como parâmetro, essa na realidade não recebe o vetor na sua totalidade, mas apenas o endereço inicial do vetor, pois estamos passando v que é igual a &v[0].
Se passarmos um endereço, então a variável que 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 um ponteiro recebendo o respectivo parâmetro.
Passagem de Vetores para funções
#include <stdio.h> void exibirVetor( int * ptr, int tam ){ int i;
for (i = 0; i < tam; i++) { printf("%i ", *(ptr + i)); } } void main(){ int vetor[] = {1, 2, 3, 4, 5}; exibirVetor(vetor, 5); getchar(); }
Ponteiro e Vetor Conclusão – Variáveis para vetores podem ser declaradas como sendo apontadores, pois os elementos do vetor, individualmente, têm o mesmo tratamento independente se a variável que os armazena é um vetor ou um apontador.
char vetor[5] equivale a char *vetor;
– Versões com ponteiros são mais rápidas!
Ponteiro e String Pode-se criar e manipular uma string fazendo uso apenas de um ponteiro.
Exemplo:
char *palavra = “exemplo”; for(; *palavra != ‘\0’; palavra++) printf(“%c ”, *palavra);
Desafios !! - Usando ponteiro para string escreva uma função que mostre a string recebida por parâmetro na tela pela ordem em que está escrita e pela ordem contrária.
- Usando ponteiro para string e diferença entre ponteiros escreva uma função que calcule o comprimento de uma string recebida por parâmetro. Obs.: Não pode usar a função strlen!
Ponteiro para Ponteiro
Uma vez que os ponteiros ocupam espaço em memória, é possível obter a sua posição através do operador de endereço &
Pergunta: Se quisermos armazenar o endereço de um ponteiro, qual o tipo da variável que irá recebê-lo?
Ponteiro para Ponteiro Resposta:
– Suponha uma variável do tipo int chamada x – Se quisermos 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.
int *ptr_x;
– Se quisermos armazenar o endereço desse ponteiro, seguimos exatamente os mesmos passos int
**ptr_ptr_x;
Ponteiro para Ponteiro Resposta: – Os passos podem ser aplicados sucessivamente para qualquer número de asteriscos
• int ****ptr = NULL; /* Válido */
– Ponteiro para ponteiro para ponteiro para ponteiro para inteiro! – Para chegar no destino final temos que fazer 4 indireções!
Um programa que use isso é difícil de entender e pode ficar muito lento!
Ponteiro para Ponteiro #include <stdio.h> void main(){ int x = 5; int * ptr_x; /* Ponteiro para x */ int ** ptr_ptr_x; /* Ponteiro para o ponteiro de x */ /* Carga inicial dos ponteiros */ ptr_x = &x; ptr_ptr_x = &ptr_x;
printf("x = %i e &x = %i\n", x, &x); printf("x = %i e &x = %i\n", *ptr_x, ptr_x); printf("x = %i e &x = %i\n", **ptr_ptr_x, *ptr_ptr_x); getchar();
}
Ponteiro para Ponteiro
Ponteiro para Ponteiro Aplicação
– Uma aplicação de ponteiros para ponteiros está nas strings, já que strings são vetores, que por sua vez são ponteiros.
– Um vetor de strings seria justamente um ponteiro para um ponteiro.
Ponteiro para Ponteiro ATENÇÃO
– Ponteiro é uma variável que não tem memória própria associada, ela apenas contém o espaço para conter um endereço.
– Portanto, só se pode utilizar o endereçamento através do ponteiro depois que este está apontando para algum objeto já existente.
– Não se deve fazer cargas iniciais de objetos apontados por um ponteiro ainda não iniciado –
Exemplo: int * p; *p = 234;
Ponteiro para Void O termo void aplicado a um ponteiro significa um ponteiro que pode acessar qualquer tipo de dado
Sintaxe: void * ptr;
Exemplo:
void main(){ void * ptr; int x = 10; ptr = &x; printf("x = %d e &x = %p", x, &x); printf("\nx = %d e &x = %p", *((int*)ptr), ptr); getchar();
Vamos em frente !!!
UFA !!!