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]