![]() |
|
Esse endereço normalmente é a posição de uma outra variável na memória.
Se uma variável contém o endereço de uma outra, então a primeira variável é dita apontar para a segunda. 3.1. Declaração de Ponteiros A declaração de uma variável do tipo ponteiro (ou apontador) consiste do tipo base (aquele para o qual o ponteiro vai apontar), um * e o nome da variável.
A forma geral é:
tipo *nome; ou tipo* nome;
char *meuString; ponteiro para caracteres
float *raizQuadrada; ponteiro para real.
Caso especial:
void *simplesPonteiro; ponteiro
genérico.
Declarações que também devolvem ponteiros:
char nome[30];
nome sozinho é também um ponteiro para caracter,
que aponta para o primeiro elemento
do nome.
Exemplo:
main ()
{
char *apontaPraNome;
int *numero;
.......
}
main ()
{
int *aponta;
int valor1, valor2;
valor1 = 5; // inicializa valor1 com 5
aponta = &valor1; // aponta recebe o endereço
// de valor1, ou seja:
// passa a apontar para valor1
valor2 = *aponta; // valor2 recebe o valor
// apontado por aponta, nesse
// caso 5, pois aponta possui
// como valor o endereço de
// valor1
}
Precedência: Tanto o & como
o * possuem precedência maior do que todos os outros operadores,
com exceção do menos unário, que possue a mesma.
int valor; int *aponta; valor = *aponta++
Isto é muito útil, pode porém, ser também muito perigoso, pois permite ao programador uma liberdade que em nenhuma outra linguagem de programação (exceto os assemblers) é possível.
int *p1, *p2, x;
x = 4;
p1 = &x; /* p1 passa a apontar para x */
p2 = p1; /* p2 recebeu o valor de p1, que é */
/* o endereço de x, ou seja: p2 */
/* também aponta para x. */
printf ("%p", p2 ); /* imprime o endereço de x */
printf ("%i", *p2 ); /* imprime o valor apontado por */
/* p2, seja: o valor de x. */
int *p1, *p2, *p3, *p4, x=0; p1 = &x; p2 = p1++; p3 = p2 + 4; p4 = p3 - 5; /* p4 acaba tendo o mesmo valor que p1 */ /* no começo. */ /* Note que p1 foi incrementado e */ /* agora tem o valor (&x + 1). */
int *p, *q;
....
if (p < q)
printf("p aponta para um endereço menor que o de q");
é um trecho de programa perfeitamente
válido em "C".
Para resolver:
tipo Pilha {
inteiro dados[Maxpilha];
inteiro *topo;
};
Inteiro FUNÇÃO empilha(inteiro
dado)
início
SE (pilhaCheia)
ENTÃO
RETORNE(ErroPilhaCheia);
SENÃO
"Se houver espaco, incremento o ponteiro topo
e faco o valor apontado por topo receber o novo dado"
aPilha.topo <- aPilha.topo + 1.
*(aPilha.topo) <- dado;
RETORNE(aPilha.topo);
FIM
SE
fim;
FUNÇÃO inicializaPilha()
início
"Fazemos
a topo apontar para um endereco de memoria
anterior ao inicio do vetor dados para simbolizar
que está vazia. "
aPilha.topo
<- aPilha.dados - 1;
fim;
Booleano FUNÇÃO pilhaVazia()
início
SE (aPilha.topo
< aPilha.dados) ENTÃO
"O topo está apontando para um endereço
de memória
anterior ao próprio início da pilha.
Segundo a nossa
definição, isto significa que a pilha está vazia.
"
RETORNE(Verdade)
SENÃO
RETORNE(Falso);
fim;
Exemplo:
char nome[30] = "José da Silva";
char *p1, *p2;
char car;
int i;
p1 = nome; // nome sozinho é um ponteiro
// para o 1º elemento de nome[].
car = nome[3]; // Atribui 'é' a car.
car = p1[0]; // Atribui 'J' a car. Válido.
p2 = &nome[5]; //Atribui a p2 o endereço da 6ª
// posição de nome, no caso 'd'.
printf( "%s", p2); // Imprime "da Silva"...
p2 = p1; // Evidentemente válido.
p2 = p1 + 5; // Equivalente a p2 = &nome[5]
printf( "%s",(p1 + 5)); // Imprime "da Silva"...
printf( "%s",(p1 + 20)); // Cuidado: Imprime lixo!!
for (i=0; strlen(nome)- 1; i++)
{
printf ("%c", nome[i]); // Imprime 'J','o','s',etc
p2 = p1 + i;
printf ("%c", *p2); // Imprime 'J','o','s',etc
}
int *vetor[30]; /* Vetor de 30 ponteiros para */ /* números inteiros. */ int a=1, b=2, c=3; vetor[0] = &a; /* vetor[0] passa a apontar p/a. */ vetor[1] = &b; vetor[2] = &c; printf ( "a: %i, b: %i", *vetor[0], *vetor[1] ); /* Imprime "a: 1, b: 2"... */
A operação acima foi possível porque com a declaração de a,b e c este espaço foi alocado.
As posições 0,1 e 2 do vetor só apontam para as posições de memória ocupadas por a, b e c.
char *mensagem[] = { /* vetor inicializado */
"arquivo não encontrado",
"erro de leitura",
"erro de escrita",
"impossível criar arquivo"
};
void escreveMensagemDeErro (int num)
{
printf ("%s\n", mensagem[num]);
}
main ()
{
escreveMensagemDeErro( 3 );
}
No caso acima, nem parece que estamos usando
ponteiros. Se quiséssemos fazer o mesmo com inteiros, por exemplo
em uma rotina que imprime todos os valores apontados por um vetor de inteiros,
já seria diferente:
int *vetor[40];
void imprimeTodos ()
{ int i;
for (i=0; i < 40; i++) printf ("%i\n", *vetor[i]);
}
#include <stdio.h>
main ()
{
int x, *p, **q; // q é um ponteiro para um
// ponteiro a inteiro.
x = 10;
p = &x; // p aponta para x
q = &p; // q aponta para p
printf ("%i\n", **q); // imprime 10...
}
#include <stdio.h>
char tecla;
char *a = "Bananarama";
char b[80] = "uma coisa besta";
char *c[5];
void teste1 (char *d[] )
{
printf( "Teste1: d[0]:%s e d[1]:%s\n\n", d[0], d[1]);
}
void teste2 (char **d )
{
printf( "Teste2: d[0]:%s e d[1]:%s\n", d[0], d[1]);
printf( "Teste3: d[0]:%s e d[1]:%s\n", *d, *(d + 1));
}
main ()
{
c[0] = a;
c[1] = b;
printf( "a: %s e b: %s\n\n", a, b);
printf( "c[0]: %s e c[1]: %s\n\n", c[0], c[1]);
teste1 ( c );
teste2 ( c );
}
[Capítulo 4]