PONTEIROS
Profª Ms. Engª Elaine Cecília Gatto
Curso de Bacharelado em Engenharia de Computação
Universidade do Sagrado CoraçãO – USC
Bauru/SP
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;
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 argumentos 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;
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;
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;
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!
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;
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
7
count referencia
diretamente uma
variável que contém
o valor 7

countPtr

count
7

countPtr referencia indiretamente uma
variável que contém o valor 7
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;
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;
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;
}
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;
Operadores de Ponteiros
yPtr

y
5

Representaçã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
Local na memória
da variável yPtr:
50.000

60.000

y
5

Local na memória
da variável y:
60.000

Representação gráfica de y e yPtr na memória
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;
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;
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;
}
Operadores de Ponteiros
aPtr

a

#include <stdio.h>
0022FF44
0022FF44
7
#include <stdlib.h>
int main(){
Nesta parte do programa, as variáveis estão sendo
int a;
declaradas e inicializadas. A variável a do tipo int
int *aPtr;
recebe o valor 7. O ponteiro para um inteiro, aPtr,
a = 7;
recebe o endereço da variável a, que é do tipo int.
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;
}
Operadores de Ponteiros
aPtr

a

#include <stdio.h>
0022FF44
0022FF45
7
#include <stdlib.h>
int main(){
int a;
int *aPtr;
Imprimindo o local da memória da
a = 7;
variável int a como um inteiro
aPtr = &a;
hexadecimal. Observe que o valor do
printf("Endereco de a = %p n", &a);
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;
}
Operadores de Ponteiros
aPtr

a

#include <stdio.h>
0022FF44
0022FF45
7
#include <stdlib.h>
int main(){
int a;
int *aPtr;
Imprimindo os valores da variável int a e
a = 7;
do ponteiro para um inteiro aPtr. Observe
aPtr = &a;
que aqui utiliza-se %d e não %p. Note
printf("Endereco de a = %p n", &a);
que aqui estamos usando *aPtr e não
printf(“Valor de aPtr = %p n", aPtr);
apenas aPtr. Também na variável a, usaprintf(“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;
}
Operadores de Ponteiros
aPtr

a

#include <stdio.h>
0022FF44
0022FF44
7
#include <stdlib.h>
int 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 à
variável aPtr em qualquer
system("Pause");
ordem,então os operadores & e *
return 0;
são complementos um do outro
}
Recapitulando: precedência de
operadores
Operadores

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
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;
Operações com ponteiros
#include <stdio.h>
#include <stdlib.h>
int main(){

//declarações
unsigned int x=5, y=6;
unsigned int *px, *py;
//atribuições
px = &x;
py = &y;

printf("n Comparacoes ");
if(px<py){
printf("py-px = %u n", (px-py));
//subtraindo
}
else{
printf("px-py = %u n", (py-px));
//subtraindo
}
Operações com ponteiros
printf("n px = %p n", px);

py++; //incrementando py

printf("*px = %u n", *px);
//operador indireto

printf("n Apos incrementar
py: n ");

printf("&px = %p n", &px);
//operador de endereços

printf("n py = %p n", py);

printf("n py = %p n", py);

printf("*py = %u n", *py);
//operador indireto

printf("*py = %u n", *py);
//operador indireto

printf("&py = %p n", &py);
//operador de endereços

printf("&py = %p n", &py);
//operador de endereços
Operações com ponteiros
px=py+5; //somando inteiros
printf("n Apos somar py+5 n ");
printf("n px = %p n", px);
printf("*px = %u n", *px); //operador indireto
printf("&px = %p n", &px); //operador de endereços

printf("n px-py = %u n n", (px-py));
system("Pause");
return 0;
}
Operações com ponteiros
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.
Operações com ponteiros
• Ilustrando:
Local na
memória

3000 3004 3008 3012 3016

Antes da soma

a[0] a[1] a[2] a[3] a[4]

Variável de ponteiro aPtr

Local na
memória

3000 3004 3008 3012 3016

a[0] a[1] a[2] a[3] a[4]

Variável de ponteiro aPtr

Após a soma
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--;
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)
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.
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;
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;
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:
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;
}
Passando argumentos por
referê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:
Passando argumentos por
referê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 inteiro
int cubo(int n){
return n*n*n;
}
Passando argumentos por
referê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 inteiro
void cubo(int *nPtr){
*nPtr = (*nPtr) * (*nPtr) * (*nPtr);
}
Passando argumentos por
referê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 inteiro
void reajuste(float *preco, float *reaj){
*reaj = *preco * 0.2;
*preco *= 1.2;
}

Linguagem C - Ponteiros

  • 1.
    PONTEIROS Profª Ms. EngªElaine Cecília Gatto Curso de Bacharelado em Engenharia de Computação Universidade do Sagrado CoraçãO – USC Bauru/SP
  • 2.
    Introdução • Ponteiros estãoentre 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ãoutilizados 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 argumentos 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 alocame 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óriado 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 linhaacima 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ávelcount é 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 7 count referencia diretamente uma variável que contém o valor 7 countPtr count 7 countPtr referencia indiretamente uma variável que contém o 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 devemser 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: paraconhecer 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 5 Representaçãográ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 Local na memória da variável yPtr: 50.000 60.000 y 5 Local na memória da variável y: 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 0022FF44 7 #include <stdlib.h> int main(){ Nesta parte do programa, as variáveis estão sendo int a; declaradas e inicializadas. A variável a do tipo int int *aPtr; recebe o valor 7. O ponteiro para um inteiro, aPtr, a = 7; recebe o endereço da variável a, que é do tipo int. 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; }
  • 18.
    Operadores de Ponteiros aPtr a #include<stdio.h> 0022FF44 0022FF45 7 #include <stdlib.h> int main(){ int a; int *aPtr; Imprimindo o local da memória da a = 7; variável int a como um inteiro aPtr = &a; hexadecimal. Observe que o valor do printf("Endereco de a = %p n", &a); 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> 0022FF44 0022FF45 7 #include <stdlib.h> int main(){ int a; int *aPtr; Imprimindo os valores da variável int a e a = 7; do ponteiro para um inteiro aPtr. Observe aPtr = &a; que aqui utiliza-se %d e não %p. Note printf("Endereco de a = %p n", &a); que aqui estamos usando *aPtr e não printf(“Valor de aPtr = %p n", aPtr); apenas aPtr. Também na variável a, usaprintf(“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> 0022FF44 0022FF44 7 #include <stdlib.h> int 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 à variável aPtr em qualquer system("Pause"); ordem,então os operadores & e * return 0; são complementos um do outro }
  • 21.
    Recapitulando: precedência de operadores Operadores Associatividade Tipo ()[] Esquerdapara 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> #include <stdlib.h> int main(){ //declarações unsigned int x=5, y=6; unsigned int *px, *py; //atribuições px = &x; py = &y; printf("n Comparacoes "); if(px<py){ printf("py-px = %u n", (px-py)); //subtraindo } else{ printf("px-py = %u n", (py-px)); //subtraindo }
  • 24.
    Operações com ponteiros printf("npx = %p n", px); py++; //incrementando py printf("*px = %u n", *px); //operador indireto printf("n Apos incrementar py: n "); printf("&px = %p n", &px); //operador de endereços printf("n py = %p n", py); printf("n py = %p n", py); printf("*py = %u n", *py); //operador indireto printf("*py = %u n", *py); //operador indireto printf("&py = %p n", &py); //operador de endereços printf("&py = %p n", &py); //operador de endereços
  • 25.
    Operações com ponteiros px=py+5;//somando inteiros printf("n Apos somar py+5 n "); printf("n px = %p n", px); printf("*px = %u n", *px); //operador indireto printf("&px = %p n", &px); //operador de endereços printf("n px-py = %u n n", (px-py)); system("Pause"); return 0; }
  • 26.
  • 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 memória 3000 3004 3008 3012 3016 Antes da soma a[0] a[1] a[2] a[3] a[4] Variável de ponteiro aPtr Local na memória 3000 3004 3008 3012 3016 a[0] a[1] a[2] a[3] a[4] Variável de ponteiro aPtr Após a soma
  • 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 • Umponteiro 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 • Ocompilador 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ãousados 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 por referênciacom 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 por referênciacom 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 inteiro int cubo(int n){ return n*n*n; }
  • 38.
    Passando argumentos por referênciacom 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 inteiro void cubo(int *nPtr){ *nPtr = (*nPtr) * (*nPtr) * (*nPtr); }
  • 39.
    Passando argumentos por referênciacom 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 inteiro void reajuste(float *preco, float *reaj){ *reaj = *preco * 0.2; *preco *= 1.2; }