Bóson Treinamentos em Ciência e Tecnologia

Ponteiros em C – Aritmética de Ponteiros

Adição e subtração de ponteiros em linguagem C

Aritmética de Ponteiros

Na lição anterior definimos o que são ponteiros, como declará-los e como realizar sua atribuição. Vamos agora abordar a aritmética de ponteiros em linguagem C.

Há duas operações aritméticas que podemos efetuar com ponteiros: adição de ponteiros e subtração de ponteiros. Além disso, também é possível comparar dois ponteiros entre si.

Suponha dois ponteiros, pont1 e pont2. pont1 aponta para um inteiro de 16 bits, cujo endereço é 5000. Vamos incrementar esse ponteiro (somar uma posição a ele) por meio do operador de incremento ++:

pont1++;

Qual será o valor contido em pont1 agora? 

O valor em pont1 será o endereço 5002, e não 5001, como era de se esperar por conta do incremento, pois sempre que um ponteiro é incrementado (ou decrementado), ele irá apontar para a posição de memória do próximo elemento de seu tipo (ou para a posição anterior, no caso do decremento).

Como um inteiro de 16 bits possui 2 bytes, o valor dese ponteiro é incrementado em duas unidades, e não em apenas uma. Já ponteiros de caractere sempre são incrementados ou decrementados em uma unidade, coo na aritmética normal, pois caracteres ocupam apenas um byte na memória.

Ou seja, a aritmética de ponteiros é baseada em seu tipo declarado.

Da mesma forma, se usarmos um ponteiro de inteiro de 32 bits, ao incrementá-lo seu endereço (no exemplo) passará a ser o endereço 5004, 4 “unidades” à frente, pois 32 bits equivalem a 4 bytes (32 / 8 bits).

Portanto, a aritmética de ponteiros lida com os endereços apontados por eles, e não com o conteúdo das variáveis apontadas. Fique atento a esse detalhe!

Tamanho de uma variável ponteiro

O tamanho de uma variável é um aspecto muito importante para o programador. Precisamos saber quanto espaço na memória uma variável ocupa quando é utilizada, para que seja possível escrever programas enxutos e que executem com boa performance. Isso é particularmente importante quando desenvolvemos programas para dispositivos embarcados, os quais, no geral, contam com quantidade restrita de memória disponível.

Dependendo da plataforma, uma variável pode ter tamanhos que variam de 8 a 64 bits. Por exemplo, em uma plataforma de 32 bits, uma variável do tipo int ocupará o espaço de 4 bytes (32 / 8 = 4).

O código a seguir nos permite verificar o tamanho na memória utilizado por ponteiros de diferentes tipos, usando o operador sizeof:

#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
int main()
{
 setlocale(LC_ALL, "");
 char caractere;
 int inteiro;
 double duplo;
 int *inteiro_ptr;
 char *caractere_ptr;
 double *duplo_ptr;
 caractere_ptr = &caractere;
 inteiro_ptr = &inteiro;
 duplo_ptr = &duplo;
 printf("Tamanho de um ponteiro de inteiro = %d valor = %p\n", sizeof(inteiro_ptr),inteiro_ptr);
 printf("Tamanho de um ponteiro de char = %d valor = %p\n", sizeof(caractere_ptr),caractere_ptr);
 printf("Tamanho de um ponteiro de double = %d valor = %p\n", sizeof(duplo_ptr),duplo_ptr);
 return 0;
}

A tabela a seguir mostra os tamanhos típicos de tipos de dados, em bytes, encontrados na maioria dos sistemas:

Tipo de dado Tamanho em bytes
byte 1
char 1
short 2
int 4
long 8
float 4
double 8

Adição e subtração em ponteiros

Tomemos como exemplo a expressão a seguir:

pont1 = pont1 + 40;

Essa declaração faz com que o ponteiro pont1 passe a apontar para o quadragésimo elemento do tipo declarado para o ponteiro a partir da posição apontada atualmente por ele. A mesma ideia se aplica à subtração de ponteiros, porém obviamente com o ponteiro apontando para posição anterior na memória RAM do sistema.

Note que a nova posição (quadragésimo elemento no exemplo) depende do tipo declarado no ponteiro. Por exemplo, para um ponteiro de inteiro de 32 bits isso significa 40 posições x 4 bytes = 160 posições à frente (A0 em hexadecimal).

Não podemos efetuar outras operações com ponteiros além da adição e subtração, com multiplicação e divisão, e nem podemos usar operadores de deslocamento bit a bit.

Vejamos um código de exemplo que mostra as operações de adição e subtração de ponteiros:

#include <stdio.h>
#include <stdlib.h>
#include <locale.h>

int main()
{
 setlocale(LC_ALL, " ");
 int a;
 a = 30;
 int *pont1;
 pont1 = &a;
 printf("Endereço de a: %p\n", pont1);
 pont1++;
 printf("Endereço do ponteiro incrementado: %p\n", pont1);
 pont1 = pont1 + 10;
 printf("Somando 40 ao ponteiro pont1: %p\n", pont1);
 pont1--;
 printf("Decrementando o ponteiro: %p\n", pont1);
 return 0;
}

Podemos ver o resultado da execução desse código na figura a seguir:

Inicialmente, podemos ver que o ponteiro pont1 apontava para o endereço de memória 0x0060FF08 (expresso em hexadecimal), onde se localiza a variável a criada.

Após o incremento (pont1++), ele passa a apontar para a posição xFF0C, que se encontra C – 8 = 4 endereços à frente da posição inicial; lembre-se de que temos aqui um inteiro de 32 bits (32 / 8 = 4).

Então, somamos 10 ao ponteiro (pont1 = pont1 + 10), que passa a apontar para o endereço xFF34. Note que, em hexadecimal,  34 – 0C = 28, que convertido para decimal é igual a 10.

E, finalmente, decrementamos o ponteiro (pont1–), que finaliza apontando para o endereço de memória xFF30, 4 posições a menos do que no comando anterior.

Comparação de Ponteiros

Podemos efetuar a comparação de ponteiros usando os operadores de comparação padrão – apesar de esta técnica não ter tanta utilidade na prática.

O código a seguir mostra a comparação entre ponteiros:

#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
int main()
{
 setlocale(LC_ALL, "");
 int vetor[] = {10, 30, 20};
 int *p0 = vetor;
 int *p1 = vetor + 1;
 int *p2 = vetor + 2;
 int *p3 = p2;
 printf("p2 > p0: %d\n", p2 > p0);
 printf("p0 > p1: %d\n", p0 > p1);
 printf("p2 < p0: %d\n", p2 < p0);
 printf("p3 = p2: %d\n", p3 == p2);
 return 0;
}

O resultado mostrado será o valor 1 para comparação verdadeira e 0 para comparação falsa, como podemos ver na figura a seguir:

Anterior: Ponteiros em C – Introdução

Próxima lição: Indireção múltipla de ponteiros

 

Sair da versão mobile