Não apenas o conteúdo de ponteiros podem tomar parte em expressões aritméticas. C também suporta o conceito de operações sobre endereços, embora as operações que possam ser utilizadas neste caso sejam limitadas. Tais operações definem a aritmética de ponteiros.
Para apresentar o conceito de aritmética de ponteiros, considere o seguinte exemplo:
main() { int arr[10]; /* arr: arranjo com 10 inteiros */ int *el; /* el: ponteiro para um inteiro */ int i; el = &arr[0]; /* inicializa ponteiro */ /* inicializa conteudo do arranjo via ponteiro */ for (i=0; i<10; ++i) *(el + i) = 0; }
O ponteiro el aponta inicialmente para o primeiro elemento do
arranjo arr, ou seja, arr[0]
-- &arr[0]
é o
endereço deste elemento. Assim, para acessar este elemento através do
ponteiro, a expressão *el
poderia ser utilizada. No entanto, é
possível também acessar outros elementos do arranjo através do ponteiro.
Para acessar o elemento seguinte, a expressão *(el+1)
retorna o
endereço do próximo inteiro armazenado após o endereço el, ou
seja, o endereço de arr[1]
. Portanto, o que a instrução interna ao
laço no exemplo está realizando é o acesso a cada elemento do arranjo
através de um ponteiro.
Um aspecto fundamental da aritmética de ponteiros é que ela libera o
programador de saber qual a dimensão alocada para cada tipo de dado.
Quando um ponteiro é incrementado, este incremento irá refletir o tamanho
do tipo da variável que está sendo apontada. Assim, o exemplo acima
funcionará independentemente da máquina no qual ele for executado, ocupe a
representação de um inteiro dois ou quatro bytes. Quando a expressão
el+i
é encontrada, o endereço do i-ésimo inteiro após o
endereço el
é obtido -- ou seja, esta expressão aponta para o
elemento arr[i]
.
A aritmética de ponteiros está limitada a quatro operadores: soma, subtração, incremento e decremento. Outra limitação é que, no caso de soma, o outro operando além do ponteiro deve ser uma expressão (ou variável ou constante) inteira. A subtração de dois ponteiros para um mesmo tipo de dado é uma operação válida, retornando o número de elementos entre os dois ponteiros. A comparação entre dois ponteiros também é uma operação legal.
Há uma única exceção ao uso legal de aritmética de ponteiros: quando um ponteiro é definido para o tipo void. Neste caso, a variável ponteiro contém um endereço genérico, sobre um tipo que não pode ser determinado. Portanto, operações aritméticas sobre este tipo de ponteiro não são permitidas.