• Like
Aula 6   pc - slides
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

Aula 6 pc - slides

  • 692 views
Published

 

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
692
On SlideShare
0
From Embeds
0
Number of Embeds
0

Actions

Shares
Downloads
85
Comments
0
Likes
1

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. Programação deComputadoresAula 606/09/2012Profª Ms. Engª Elaine Cecília GattoUnidade 5: PonteirosCurso de Bacharelado em Engenharia de ComputaçãoUniversidade do Sagrado Coração – USCBauru/SP
  • 2. Introdução• Ponteiros estão entre as capacidades mais difícieis de se dominar na linguagem C;• Ponteiros permitem: Simular uma chamada por referência; Criar e manipular estruturas dinâmicas de dados; Estruturas de dados podem crescer e encolher no tempo de execução; Listas interligadas, filas, pilhas, árvores, etc., são exemplos de estruturas de dados dinâmicas;• Ponteiros são variáveis cujos valores são endereços de memória;• Uma variável comum contém claramente um valor específico;
  • 3. Introdução• Ponteiros são utilizados em situações em que o uso do nome de uma variável não é permitido ou é indesejável;• Ponteiros fornecem maneiras com as quais as funções podem realmente modificar os agrumentos que recebem – passagem por referência;• Ponteiros passam matrizes e strings mais convenientemente de uma função para outra;• Ponteiros manipulam os elementos de matrizes mais facilmente, por meio da movimentação de ponteiros para elas – ou parte delas – no lugar de índices entre colchetes;
  • 4. Introdução• Ponteiros alocam e desalocam memória dinamicamente no sistema;• Ponteiros passam para uma função o endereço de outra função.• Um ponteiro é um tipo especial de variável que foi concebida para conter o endereço de outra variável;• Um ponteiro armazena um endereço de memória, que é a localização de outra variável;• Uma variável aponta para outra variável quando a primeira contém o endereço da segunda;
  • 5. Introdução• A memória do computador é dividida em bytes, numerados de zero até o limite da memória do computador;• Esses números são chamados de endereços de bytes;• Um endereço é uma referencia que o computador usa para localizar variáveis;• Seu endereço é o do primeiro byte ocupado por ela;• Os programas, quando carregados, ocupam uma certa parte da memória;• Toda variável e toda função dos programas em C começam em um endereço particular, que é chamado endereço da variável ou da função;
  • 6. Introdução• Um ponteiro, diferentemente de uma variável comum, contém um endereço de uma variável que contém um valor específico;• Uma variável comum referencia um valor diretamente;• Um ponteiro referencia um valor indiretamente;• INDIREÇÃO: é a referência de valor por meio de um ponteiro;• Ponteiros devem ser definidos antes de sua utilização, como qualquer outra variável;• Exemplo: int *countPtr, count;• O que faz esse linha de código? Pense!
  • 7. Introdução• A linha acima pode ser reescrita da seguinte forma: int *countPrt; int count;• Note que foram criadas duas variáveis do tipo INT, entretanto, uma delas é um ponteiro;• Todo ponteiro necessita do símbolo * antes do nome da variável;• Portanto, int *countPtr especifica que a variável countPtr é do tipo int * - um ponteiro para um inteiro, e pode ser lido de duas formas: countPtr é um ponteiro para int; countPtr aponta para um objeto do tipo int;
  • 8. Introdução • A variável count é definida para ser um inteiro, e não um ponteiro para int; • Se quisermos que count seja um ponteiro, devemos alterar a declaração int count para int *count; count countPtr count 7 7count referencia countPtr referencia indiretamente umadiretamente uma variável que contém o valor 7variável que contémo valor 7
  • 9. Introdução• Cuidado: A notação *, usada para declarar variáveis de ponteiro, não distribui para todos os nomes de variáveis em uma declaração; Cada ponteiro precisa ser declarado com o * prefixado ao nome; Exemplo: se você quiser declarar xPtr e yPtr como ponteiros int, então use int *xPtr, *yPtr;• Dica; Inclua as letras Ptr nos nomes de variáveis de ponteiros para deixar claro que essas variáveis são ponteiros, e, portanto, precisam ser tratadas de modo apropriado; Inicialize os ponteiros para evitar resultados inesperados;
  • 10. Introdução• Ponteiros devem ser inicializados quando são definidios ou então em uma instrução de atribuição;• Ponteiros podem ser inicializados com NULL, zero, ou um endereço;• NULL: não aponta para nada, é uma constante simbólica;• Inicilizar um ponteiro com zero é o mesmo que inicializar com NULL;• Nesse caso zero é convertido em um ponteiro apropriado;• Zero é o único valor inteiro que pode ser atribuídó diretamente a um ponteiro. int *xPtr = NULL; int *yPtr = 0;
  • 11. Introdução• Exemplo: para conhecer o endereço ocupado por uma variável usamos o operador de endereços &. O resultado da operação é um ponteiro constante.#include <stdio.h>#include <stdlib.h> int main(){ int i, j, k; printf(“Endereço de i = %p n”, &i); printf(“Endereço de j = %p n”, &j); printf(“Endereço de k = %p n”, &k); system(“Pause”); return 0;}
  • 12. Operadores de Ponteiros• & = operador de endereço = é um operador unário que retorna o endereço de seu operando;• Exemplo: int y = 5; int *yPtr; yPtr = &y• A terceira instrução atribui o endereço da variável y à variável de ponteiro yPtr;• A variável yPtr aponta para y;
  • 13. Operadores de Ponteiros yPtr y 5Representação gráfica de um ponteiro apontando para uma variável inteira na memória• Suponha que a variável y esteja armazenada no local 60.000 da memória;• Suponha que a variável yPtr esteja armazenada no local 50.000 da memória;• O operando do operador de endereço precisa ser uma variável;• O operador de endereço não pode ser aplicado a constantes, expressões ou variáveis declaradas da classe register. yPtr y Local na memória Local na memória da variável yPtr: 60.000 5 da variável y: 50.000 60.000 Representação gráfica de y e yPtr na memória
  • 14. Operadores de Ponteiros• O operador unário *, retorna o valor do objeto apontado por seu operando;• O operardor indireto * é unário e opera sobre um endereço ou ponteiro;• O resultado da operação é o nome da variável localizada nesse endereço – apontada;• O nome da variável representa o seu valor ou conteúdo;• Por fim, resulta o valor da variável apontada;• Exemplo: printf(“%d”, *yPtr);• Imprime o valor da variável y;• O uso de * é chamado de desreferenciação de um ponteiro;
  • 15. Operadores de Ponteiros• O operador de endereços & opera sobre o nome de uma variável e resulta o seu endereço, já o operador indireto * opera sobre o endereço de uma variável e resulta o seu nome.• Dica: • Acessar um conteúdo com um ponteiro que não foi devidamente inicializado ou que não foi designado para apontar um local específico na memória é um erro. Isso poderia causar um erro fatal no temp de execução, ou poderia acidentalmente modificar dados e permitir que o programa fosse executado até o fim com resultados incorretos;
  • 16. Operadores de Ponteiros• Exemplo: o código a seguir demonstra a utilização dos operadores & e *. %p mostra o local da memória como um inteiro hexadecimal na maioria das plataformas.#include <stdio.h>#include <stdlib.h>int main(){ int a; int *aPtr; a = 7; aPtr = &a; printf("Endereco de a = %p n", &a); printf("O valor de aPtr = %p n", aPtr); printf("O valor de a = %d n", a); printf("O valor de aPtr = %d n", *aPtr); printf("* e & sao complementos um do outro: n"); printf("&*aPtr = %p n", &*aPtr); printf("*&aPtr = %p n", *&aPtr); system("Pause"); return 0;}
  • 17. Operadores de Ponteiros aPtr a#include <stdio.h> 0022FF44 7 0022FF44#include <stdlib.h>int main(){ int a; Nesta parte do programa, as variáveis estão sendo int *aPtr; declaradas e inicializadas. A variável a do tipo int a = 7; recebe o valor 7. O ponteiro para um inteiro, aPtr, aPtr = &a; recebe o endereço da variável a, que é do tipo int. printf("Endereco de a = %p n", &a); printf("O valor de aPtr = %p n", aPtr); printf("O valor de a = %d n", a); printf("O valor de aPtr = %d n", *aPtr); printf("* e & sao complementos um do outro: n"); printf("&*aPtr = %p n", &*aPtr); printf("*&aPtr = %p n", *&aPtr); system("Pause"); return 0;}
  • 18. Operadores de Ponteiros aPtr a#include <stdio.h>#include <stdlib.h> 0022FF45 7 0022FF44int main(){ int a; int *aPtr; a = 7; Imprimindo o local da memória da aPtr = &a; variável int a como um inteiro printf("Endereco de a = %p n", &a); hexadecimal. Observe que o valor do ponteiro aPtr é o endereço da variável printf(“Valor de aPtr = %p n", aPtr); int a. printf(“Valor de a = %d n", a); printf(“Valor de aPtr = %d n", *aPtr); printf("* e & sao complementos um do outro: n"); printf("&*aPtr = %p n", &*aPtr); printf("*&aPtr = %p n", *&aPtr); system("Pause"); return 0;}
  • 19. Operadores de Ponteiros aPtr a#include <stdio.h>#include <stdlib.h> 0022FF45 7 0022FF44int main(){ int a; int *aPtr; a = 7; Imprimindo os valores da variável int a e aPtr = &a; do ponteiro para um inteiro aPtr. Observe printf("Endereco de a = %p n", &a); que aqui utiliza-se %d e não %p. Note que aqui estamos usando *aPtr e não printf(“Valor de aPtr = %p n", aPtr); apenas aPtr. Também na variável a, usa- printf(“Valor de a = %d n", a); se apenas a e não &a. printf(“Valor de aPtr = %d n", *aPtr); printf("* e & sao complementos um do outro: n"); printf("&*aPtr = %p n", &*aPtr); printf("*&aPtr = %p n", *&aPtr); system("Pause"); return 0;}
  • 20. Operadores de Ponteiros aPtr a#include <stdio.h>#include <stdlib.h> 0022FF44 7 0022FF44int main(){ int a; int *aPtr; a = 7; aPtr = &a; printf("Endereco de a = %p n", &a); printf(“Valor de aPtr = %p n", aPtr); printf(“Valor de a = %d n", a); printf(“Valor de aPtr = %d n", *aPtr); printf("* e & sao complementos um do outro: n"); printf("&*aPtr = %p n", &*aPtr); Quando os dois operadores são printf("*&aPtr = %p n", *&aPtr); aplicados consecutivamente à system("Pause"); variável aPtr em qualquer return 0; ordem,então os operadores & e *} são complementos um do outro
  • 21. Recapitulando: precedência deoperadoresOperadores Associatividade Tipo()[] Esquerda para direita Mais alta+ - ++ -- ! * & Direita para esquerda Unário*/% Esquerda para direita Multiplicativo+- Esquerda para direita Aditivo< <= > >= Esquerda para direita Relacional== != Esquerda para direita Igualdade&& Esquerda para direita And lógico|| Esquerda para direita Or lógico?: Direita para esquerda Condicional= += -= *= /= %= Direita para esquerda Atribuição, Esquerda para direita Vírgula
  • 22. Operações com ponteiros• C permite operações básicas com ponteiros;• Ponteiros são operandos válidos em expressões aritméticas, atribução e comparação;• Nem todos os operadores normalmente usados nessas expressões são válidos em conjunto com variáveis de ponteiro;• Um conjunto limitado de operações aritméticas pode ser realizado com ponteiros;• Um ponteiro pode ser incrementado ou decrementado;• Um inteiro pode ser somado/subtraído a um ponteiro;• Um ponteiro pode ser subtraído de outro ponteiro;
  • 23. Operações com ponteiros#include <stdio.h> printf("n Comparacoes ");#include <stdlib.h> if(px<py){int main(){ printf("py-px = %u n", (px-py)); //subtraindo } //declarações else{ unsigned int x=5, y=6; printf("px-py = %u n", (py-px)); unsigned int *px, *py; //subtraindo } //atribuições px = &x; py = &y;
  • 24. Operações com ponteirosprintf("n px = %p n", px); py++; //incrementando pyprintf("*px = %u n", *px); printf("n Apos incrementar//operador indireto py: n ");printf("&px = %p n", &px); printf("n py = %p n", py);//operador de endereços printf("*py = %u n", *py);printf("n py = %p n", py); //operador indiretoprintf("*py = %u n", *py); printf("&py = %p n", &py);//operador indireto //operador de endereçosprintf("&py = %p n", &py);//operador de endereços
  • 25. Operações com ponteirospx=py+5; //somando inteirosprintf("n Apos somar py+5 n ");printf("n px = %p n", px);printf("*px = %u n", *px); //operador indiretoprintf("&px = %p n", &px); //operador de endereçosprintf("n px-py = %u n n", (px-py));system("Pause");return 0;}
  • 26. Operações com ponteiros
  • 27. Operações com ponteiros• Exemplo de soma: int a[5]; aPtr = v; aPtr = &a[0]; aPtr += 2;• Suponho que o primeiro elemento esteja no local 3000 e que o inteiro esteja armazenado em 4 bytes da memória, o resultado de aPtr+=2 será 3008 pois (3000 + 2 * 4) = 3008.• Se o inteiro estiver armazenado em 2 bytes da memória, então o resultado será 3004, pois (3000 + 2 * 2) = 3004.
  • 28. Operações com ponteiros • Ilustrando: Local na 3000 3004 3008 3012 3016 Antes da soma memória a[0] a[1] a[2] a[3] a[4]Variável de ponteiro aPtr Local na 3000 3004 3008 3012 3016 memória a[0] a[1] a[2] a[3] a[4] Após a soma Variável de ponteiro aPtr
  • 29. Operações com ponteiros• Se um ponteiro estiver sendo incrementado ou decrementado em um, os operadores de incremento e decremento poderão ser usados. As instruções abaixo incrementam e decrementam o ponteiro para que ele aponte para o próximo local ou para o local anterior. No caso do vetor, aponta para o próximo elemento ou elemento anterior.• ++aPtr;• aPtr++;• --aPtr;• aPtr--;
  • 30. Operações com ponteiros• Suponha que aPtr tem o local 3000 e a2Ptr tem o local 3008, então: x = a2Ptr – aPtr;• Faz com que x receba o número de elementos do vetor aPtr para a2Ptr, resultado = 2 (duas posições).• Aritmética de ponteiros só funciona com ARRAYS (matrizes e vetores);• A menos que as variáveis de mesmo tipo sejam elementnos adjacentes de um array, elas não serão armazenadas em posições contíguas na memória (uma após a outra)
  • 31. Operações com ponteiros• Cuidado:• Usar aritmética de ponteiro em um ponteiro que não se aplique a um elemento em um array causa um erro;• Subtrair ou comparar dois ponteiros que não se referem a elementos do mesmo array causa também um erro;• Ultrapassar o final de um array ao usar a aritmética de ponteiro também causa um erro;• Dica:• A maioria dos computadores de hoje tem inteiros de 2 bytes ou 4 bytes. Algumas das máquinas mais novas utilizam inteiros de 8 bytes. Como os resultados da aritmética de ponteiro dependem do tamanho dos objetos que um ponteiro aponta, a aritmética de ponteiro é dependente da máquina.
  • 32. Ponteiro Void• Um ponteiro pode ser atribuído a outro se ambos forem do mesmo tipo, exceto quando o ponteiro for um ponteiro para void;• Exemplo: não podemos atribuir um endereço de uma variável int a um ponteiro float;• Um ponteiro para void é um ponteiro genérico que pode representar qualquer tipo de ponteiro;• Todos os tipos de ponteiro podem receber um ponteiro para void, e este pode receber um ponteiro de qualquer tipo;• Um ponteiro para void não pode ser desreferenciado;• Um ponteiro para int refere-se a 4 bytes de memória em uma máquina com inteiros de 4 bytes;
  • 33. Ponteiro Void• O compilador então sabe quanto de espaço reservar para um ponteiro do tipo int;• Mas o compilador não sabe quanto de espaço reservar, na memória, para um tipo void;• Um ponteiro para void simplesmente contém um local da memória para um tipo de dado desconhecido;• O número exato de bytes aos quais o ponteiro se refere não é conhecido pelo compilador;• Um ponteiro void é um ponteiro de propósito geral;• Atribuir um ponteiro de um tipo a um ponteiro de outro tipo se nenhum deles for do tipo void * consistem em um erro de sintaxe;
  • 34. Ponteiro Void• São usados em situações em que seja necessário que uma função receba ou retorne um ponteiro genérico e opere independentemente do tipo de dado apontado;• Qualquer endereço pode ser atribuído a um ponteiro void; void *p;• O conteúdo da variável de um ponteiro void não pode ser acessado por meio desse ponteiro;• Para isso é necessário criar outro ponteiro e fazer a conversão de tipo na atribuição;• Exemplo:
  • 35. Ponteiro Void#include <stdio.h>#include <stdlib.h>int main(){ int i=5, *pi; float f=3.2, *pf; void *pv; pv = &i; pi=(int *)pv; //CONVERSÃO printf("n *pi = %d n ", *pi); pv = &f; pf =(float *)pv; //CONVERSÃO printf("n *pf = %3.2f n n", *pf); system("PAUSE"); return 0;}
  • 36. Passando argumentos porreferência com ponteiros• Uma função pode receber diversos argumentos, mas só consegue retornar um único valor por meio do comando return;• Usando ponteiros, é possível que uma função retorne mais de um valor para a função chamadora;• Duas são as formas de passar argumentos para uma função: chamada por valor e chamada por referência;• Exemplos:
  • 37. Passando argumentos porreferência com ponteiros• USANDO CHAMADA POR VALOR#include <stdio.h>#include <stdlib.h>int cubo(int n);int main(){ int numero = 5, resultado; printf("n Valor da variavel numero: %d ", numero); //passando o número por valor à função cubo resultado = cubo(numero); printf("n Valor da varivel resultado: %d ", resultado); printf("n n"); system("PAUSE"); return 0;}//função para calcular o cubo de um numero inteiroint cubo(int n){ return n*n*n;}
  • 38. Passando argumentos porreferência com ponteiros• USANDO CHAMADA POR REFERÊNCIA#include <stdio.h>#include <stdlib.h>void cubo(int *nPtr);int main(){ int numero = 5, resultado; printf("n Valor da variavel numero: %d ", numero); //passando o número por valor à função cubo cubo(&numero); printf("n Valor da varivel resultado: %d ", numero); printf("n n"); system("PAUSE"); *nPtr na verdade é a return 0; variável numero}//função para calcular o cubo de um numero inteirovoid cubo(int *nPtr){ *nPtr = (*nPtr) * (*nPtr) * (*nPtr);}
  • 39. Passando argumentos porreferência com ponteiros• USANDO CHAMADA POR REFERÊNCIA#include <stdio.h>#include <stdlib.h>void reajuste(float *, float *);int main(){ float preco, reaj; do { printf("n Insira o preco atual: "); scanf("%f", &preco); reajuste(&preco, &reaj); printf("n Novo preco: %3.2f ", preco); printf("n O aumento foi de %3.2f ", reaj); printf("n"); } while(preco!=0.0); system("PAUSE"); return 0;}//função para calcular o cubo de um numero inteirovoid reajuste(float *preco, float *reaj){ *reaj = *preco * 0.2; *preco *= 1.2;}