![]()  | 
 | 
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]