Programação com apontadores

Introdução

Apontadores para elementos

   int a[10], *p;
   p = &a[0];

Modificar um elemento

   *p = 21;

Aritmética de apontadores

Aritmética de apontadores

Somar um inteiro

p = &a[2];

q = p + 3;

Subtrair um inteiro

p = &a[2];

q = p - 2;

Processamento de vetores

int soma_vec(int vec[], int n) {
  int *p, soma;
  soma = 0;
  for(p = &vec[0]; n>0; n--) {
    soma += *p;
    p++;
  }
  return soma;
}

Apontadores e variáveis indexadas

   int a[10];
   *a = 7;      // coloca 7 em a[0] 
   *(a+1) = 12; // coloca 12 em a[1]


Em geral:

a+i é equivalente a &a[i]
a[i] é equivalente a *(a+i)

Apontadores e variáveis indexadas (cont.)

Podemos re-escrever a inicialização do ciclo

  for(p = &vec[0]; n>0; n--) {
   ...
  }

como:

  for(p = vec; n>0; n--) {
    ...
  }

Argumentos de funções

  int soma_vec(int vec[], int n) {
     ...
  }
  ...
  int a[N];
  ...
  s = soma_vec(a, N);  

Consequências

Exemplo 1

   int soma_vec(int *vec, int n) {
     ...
   }
   int soma_vec(int vec[], int n) {
     ...
   }

Exemplo 2

   int a[100];
   ...
   s = soma_vec(&a[30], 10);
      // somar a[30], a[31], ... a[39]
   s = soma_vec(a+30, 10);

Retornar apontadores

   int *max(int *pa, int *pb) {
      if(*pa > *pb)
         return pa;
      else
         return pb;  
   } 

Retornar apontadores (cont.)

   int *p, i, j;
   ...
   p = max(&i, &j);

Cuidados ao retornar apontadores

char *f( ... ) {
   char tmp[MAX];
   ...
   return &tmp[...]; // ERRO
}

Apontador nulo

Exemplo

Definir uma função

   char *find_alpha(char *str);

(Exercício 9.9: implementar uma função análoga.)

Exemplo (cont.)

#include <stdlib.h>
#include <ctype.h>

char *find_alpha(char *str) {
   while(*str != '\0' && !isalpha(*str)) {
      str ++;
   }
   if (*str != '\0')
      return str;  // encontrou
   else
      return NULL; // não encontrou
}

Apontador nulo

   char texto[100], *ptr;
   ...
   ptr = find_alpha(texto);
   if(ptr != NULL) 
     printf("Primeira letra: %c\n", *ptr);
   else 
     printf("Não existem letras!\n"); 

Apontador nulo (cont.)

int *p = NULL;

printf("%d", *p); // ERRO

*p = 42;          // ERRO

Processamento de cadeias

Processamento de cadeias

Vamos re-implementar algumas funções sobre cadeias usando apontadores:

Comprimento (1)

unsigned comprimento(char *str) {
  unsigned len = 0;
  char *ptr = str;
  while(*ptr != '\0') {
     len ++;
     ptr ++;
  }
  return len;
}

Comprimento (2)

Versão mais "idiomática": pós-incremento na condição do ciclo.

unsigned comprimento(char *str) {
  unsigned len = 0;
  char *ptr = str;
  while(*ptr++ != '\0')
      len++;
  return len;
}

Comprimento (3)

Não é necessário a variável auxiliar ptr: podemos usar o argumento da função directamente.

unsigned comprimento(char *str) {
  unsigned len = 0;
  while(*str++ != '\0')
      len++;
  return len;
}

Copiar (1)

void copiar(char *dest, char *origem) {
   while(*origem != '\0') {
      *dest = *origem;
      dest ++;
      origem ++;
   }
   *dest = '\0';  // colocar terminador
}

Copiar (2)

Combinando a atribuição com o pós-incremento de apontadores.

void copiar(char *dest, char *origem) {
   while(*origem != '\0') 
      *dest++ = *origem++;
   *dest = '\0';  // colocar terminador
}

Concatenar

void concat(char *dest, char *origem) {
    // advançar até final do destino
   dest += comprimento(dest);
   // copia a origem
   while(*origem != '\0') 
      *dest++ = *origem++;
   *dest = '\0';
}

Comparar cadeias

Resultado 1 se as cadeias são iguais e 0 se são diferentes.

int comparar(char *str1, char *str2) {
  while(*str1 != '\0' && *str1 == *str2) {
    str1++;
    str2++;
  }
  return (*str1 == *str2);
}