Continuando o assunto abordado no primeiro artigo, veremos algumas aplicações envolvendo aritmética de ponteiro. Assim como variáveis comuns, os ponteiros também podem ter o seu conteúdo alterado utilizando operações aritméticas, contudo é necessário entender mais alguns conceitos.
Variáveis
Vimos no primeiro artigo que ao declarar uma variável, um espaço na memória é reservado. Neste ponto, é importante definir que toda variável declarada ocupa uma porção da memória, sendo que o tamanho ocupado é relativo ao tipo da variável. Um modo de obter o tamanho que um tipo de dado representa é a partir do operador sizeof. Para exemplificar, considere o código abaixo que foi executado em uma máquina de 64 bits.
printf("Size of char: %i\r\n", sizeof(char));
printf("Size of int: %i\r\n", sizeof(int));
printf("Size of float: %i\r\n", sizeof(float));
printf("Size of double: %i\r\n", sizeof(double));
A saída gerada é mostrada na Figura 1. Cabe ressaltar que o comando sizeof retorna o tamanho em bytes!
Se considerarmos uma memória endereçada byte a byte, a declaração de uma variável do tipo inteiro ocuparia 4 bytes da memória, já um double, 8 bytes. Diante disso, consideramos como endereço da variável o endereço de menor valor na região ocupada. Na Figura 2, o endereço base é indicado em vermelho.
É importante lembrar que um ponteiro também é uma variável, portanto ocupa espaço na memória. Geralmente, o tamanho de um ponteiro, independente do tipo de dados, ocupa o espaço de um inteiro.
Portanto, ao acessar o conteúdo de um endereço o tipo de dado deve ser considerado, pois diferentes tipos podem ocupar espaços diferentes da memória. Essas definições são importantes, pois um ponteiro também possui um tipo de dados e isso implicará nas operações aritméticas realizadas!
Operações com ponteiros
Apenas as operações de subtração e adição podem ser realizadas com os ponteiros. Como veremos a seguir essas operações dependem do tipo de dados que o ponteiro foi declarado. Este tópico é importante para entender a utilização de ponteiros com vetores e matrizes.
Apresentando as operações básicas de incremento e decremento fica fácil entender o que ocorre com o endereço armazenado no ponteiro quando uma das operações aritméticas é utilizada. Considere o caso mostrado na Figura 3.
Neste exemplo, temos um ponteiro e três variáveis do tipo inteiro. Considere também que essas variáveis estão alinhadas sequencialmente na memória e que o ponteiro está armazenando o endereço da variável x (endereço 104).
Para incrementar o ponteiro:
pt++;
Lembre-se que é o endereço armazenado no ponteiro que desejamos incrementar. Ao realizar a operação, o ponteiro passará a apontar para o próximo dado do seu tipo. Dito de outra maneira, ao incrementar o ponteiro o seu valor é alterado conforme o tamanho do tipo de dado que ele aponta. Diante disso, o próximo valor pt é o endereço 108, logo o ponteiro aponta para a variável y. Essa situação é ilustrada na Figura 4.
O mesmo ocorre para a operação de decremento:
pt--;
Neste caso, o ponteiro passa a apontar para o elemento anterior. De maneira geral, qualquer operação aritmética de ponteiro será realizada conforme o seu tipo base.
Por exemplo:
pt = pt + 4; // 4 x sizeof(int) = 16 bytes
Essa operação faz com que o ponteiro seja deslocado 16 bytes, ou seja, quatro elementos adiante.
Comparação de Ponteiros
A comparação de ponteiro também pode ser realizada, isto é, os endereços armazenados podem ser utilizados numa expressão relacional. Uma operação simples é a de diferenciação, ou seja, quando um ponteiro é subtraído de outro.
int diff = abs(pt_Top – pt_Base);
Com a diferenciação é possível obter a distância entre os dois ponteiros, isto é, a quantidade de elementos presentes. Diante disso, é comum que as operações de comparação sejam realizadas quando os ponteiros apontam para um objeto comum [1].
while(pt < ptTop)
{
//......
//alterar pt
}
Conclusão
Os tópicos discutidos neste artigo são de grande importância para trabalhar com ponteiros e arrays. Como demonstrado, qualquer operação aritmética de ponteiro é realizada conforme o seu tipo base. Além disso, os ponteiros podem ser comparados em uma expressão relacional. Essas características possibilitam criar e manipular estruturas de dados bem mais complexas, contudo, vale lembrar que todo cuidado é pouco ao trabalhar com ponteiros!
Referências
[1] – Livro: C, completo e total – 3ª edição revista e atualizada. Herbert Schildt.Fonte da imagem destacada: https://listamaze.com/top-10-programming-languages-for-job-security/











Grande Fernando, parabéns por explicar sem complicar. Exemplos simples na demonstração faz absorção do conteúdo ser muito rápida.