Aritmética com Ponteiros

Somar um inteiro (positivo ou negativo) a um ponteiro é válido em C. Isso assume que o ponteiro aponta para um elemento de um array, e avança ou recua o ponteiro o número de elementos indicado pelo inteiro. Aqui está um exemplo em que somar um inteiro positivo avança o ponteiro para elementos posteriores do mesmo array:

void
incrementing_pointers()
{
  int array[5] = { 45, 29, 104, -3, 123456 };
  int elt0, elt1, elt4;

  int *p = &array[0];
  /* Agora p aponta para o elemento 0. Busque o valor. */
  elt0 = *p;

  ++p;
  /* Agora p aponta para o elemento 1. Busque o valor. */
  elt1 = *p;

  p += 3;
  /* Agora p aponta para o elemento 4 (o último). Busque o valor. */
  elt4 = *p;

  printf("elt0 %d  elt1 %d  elt4 %d.\n", elt0, elt1, elt4);
  /* Imprime: elt0 45  elt1 29  elt4 123456. */
}

Abaixo, um exemplo em que somar um inteiro negativo recua o ponteiro para elementos anteriores do array:

void
decrementing_pointers()
{
  int array[5] = { 45, 29, 104, -3, 123456 };
  int elt0, elt3, elt4;

  int *p = &array[4];
  /* Agora p aponta para o elemento 4 (o último). Busque o valor. */
  elt4 = *p;

  --p;
  /* Agora p aponta para o elemento 3. Busque o valor. */
  elt3 = *p;

  p -= 3;
  /* Agora p aponta para o elemento 0. Busque o valor. */
  elt0 = *p;

  printf("elt0 %d  elt3 %d  elt4 %d.\n", elt0, elt3, elt4);
  /* Imprime: elt0 45  elt3 -3  elt4 123456. */
}

Se um valor de ponteiro foi criado somando um inteiro a outro ponteiro, deve ser possível subtrair esses dois ponteiros e obter novamente o inteiro original. Isso também funciona em C:

void
subtract_pointers()
{
  int array[5] = { 45, 29, 104, -3, 123456 };
  int *p0, *p3, *p4;

  int *p = &array[4];
  /* Agora p aponta para o elemento 4 (último). Guarde o valor. */
  p4 = p;

  --p;
  /* Agora p aponta para o elemento 3. Guarde o valor. */
  p3 = p;

  p -= 3;
  /* Agora p aponta para o elemento 0. Guarde o valor. */
  p0 = p;

  printf("%d, %d, %d, %d\n",
         p4 - p0, p0 - p0, p3 - p0, p0 - p3);
  /* Imprime: 4, 0, 3, -3. */
}

A operação de soma não sabe onde começam ou terminam os arrays na memória. Tudo o que ela faz é somar o inteiro (multiplicado pelo tamanho do tipo apontado) ao valor numérico do ponteiro. Quando o ponteiro original e o resultado apontam para dentro do mesmo array, o resultado é bem definido.

O resultado da subtração entre dois ponteiros tem tipo int ou long se necessário (veja Tipos de Dados Inteiros). A forma limpa de declarar esse tipo é usando o tipo ptrdiff_t, definido no arquivo <stddef.h>.

O C define a subtração de ponteiros de forma a ser consistente com a adição ponteiro + inteiro, de modo que (p3 - p1) + p1 seja igual a p3, como em álgebra comum. A subtração entre ponteiros funciona subtraindo o valor numérico de p1 de p3, e dividindo pelo tamanho do tipo apontado. Os dois ponteiros devem apontar para dentro do mesmo array.

No C padrão, adições e subtrações não são permitidas com void *, já que o tamanho do tipo apontado não está definido nesse caso. O mesmo vale para ponteiros para funções. No entanto, essas operações funcionam no GNU C, e o "tamanho do tipo apontado" é considerado como 1 byte.

Atualizado

Isto foi útil?