Bonecos-sentados-em-cima-de-um-lapisOs ints guardam números inteiros. Os floats guardam números de ponto flutuante. Os chars guardam caracteres e os ponteiros guardam endereços de memória. Por exemplo, quando anotamos o endereço de um amigo, estamos a criar um ponteiro, neste caso ponteiro é o pedaço de papel em que fica guardado o endereço do amigo, mas afinal, qual é o sentido disto?

[clearboth]
[toggle title=”O que são Ponteiros?”]

É simples, quando anotamos o endereço de um amigo, mais tarde vamos utilizar este endereço para encontra-lo. O C funciona assim. Você anota o endereço de algo numa variável ponteiro para mais tarde utilizar. Da mesma forma, numa agenda, onde são guardados vários endereços de vários amigos, pode ser vista como uma matriz de ponteiros no C. Um ponteiro também tem um tipo. Quando você anota um endereço de um amigo você trata-o de forma diferente do que quando você anota o endereço de uma empresa. Apesar do endereço dos dois locais ter o mesmo formato (rua, número, cidade, etc.) eles indicam locais cujos conteúdos são diferentes, então os dois endereços são ponteiros de tipos diferentes. No C quando declaramos um ponteiro, informa-mos ao compilador para que tipo de variável vamos apontá-lo. Um ponteiro int aponta para um inteiro, isto é, guarda o endereço de um número inteiro.

[/toggle]
[toggle title=”Como declarar e utilizar Ponteiros?”]

Para declarar um ponteiro utilizamos a seguinte forma geral:

tipo_do_ponteiro *nome_da_variável;

É o asterisco (‘*‘) que informa o compilador de que aquela variável não vai guardar um valor mas sim um endereço para aquele tipo especificado. Abaixo encontram-se exemplos de declarações de ponteiros.

int *pt;
char *temp,*pt2;

O primeiro exemplo declara um ponteiro para um número inteiro. O segundo exemplo declara dois ponteiros para caracteres/strings. Estes ponteiros ainda não foram inicializados (como todas as variáveis do C que são apenas declaradas). Isto significa que eles apontam para um lugar indefinido. Este lugar pode estar, por exemplo, na porção da memória reservada ao sistema operacional do computador. Utilizar o ponteiro nestas circunstâncias pode levar a um bloqueio do micro, ou a algo pior. O ponteiro deve ser inicializado (e deve apontar para algum lugar conhecido) antes de ser utilizado! Para atribuir um valor a um ponteiro já declarado poderíamos igualá-lo a um valor de memória, mas, como saber a posição na memória de uma variável do nosso programa?

Seria muito difícil saber o endereço de cada variável que utilizamos, até porque estes endereços são determinados pelo compilador durante o processo de compilação e realocados na execução do programa. Podemos então deixar que o compilador faça este trabalho por nós. Para saber o endereço de uma variável basta utilizar o operador ‘&‘.

Veja o exemplo abaixo:

int count=10;
int *pt;
pt=&count;

Criamos uma variável do tipo inteiro ‘count com o valor de 10 e um ponteiro inteiro ‘pt‘. A expressão ‘&count dá-nos o endereço da variável ‘count‘, que foi armazenado no ponteiro ‘pt‘. Agora parece mais simples de entender, certo? Repare que não alteramos o valor da variável count, ou seja, ela continua com o valor 10 armazenado.

Como nós colocamos o endereço de ‘count‘ no ponteiro ‘pt‘, ele agora está “liberto” para ser utilizado. Podemos, por exemplo, alterar o valor da variável ‘count com o uso do ponteiro ‘pt‘. Portanto, vamos utilizar o operador “inverso” ao operador ‘&‘ que é o operador ‘*‘. No exemplo acima, uma vez que fizemos ‘pt=&count a expressão ‘*pt é equivalente ao próprio à variável ‘count‘. Isto significa que, se quisermos mudar o valor de ‘count‘ para 12, basta fazer *pt=12.

Vamos fazer uma pausa e voltar à nossa analogia inicial para ver o que está a acontecer. Digamos que exista uma empresa. Ela é como uma variável que já foi declarada. Você tem um papel em branco onde vai anotar o endereço da firma. O papel é um ponteiro do tipo empresa. Você liga para a empresa e pede o seu endereço, o qual você vai anotar no papel. Isto é equivalente, no C, a associar o papel à empresa com o operador &. Ou seja, o operador aplicado à empresa é equivalente a você ligar para a mesma e pedir o endereço. Uma vez de posse do endereço no papel você poderia, por exemplo, fazer uma visita à empresa. No C você faz uma visita à empresa ao aplicar o operador ‘* ano papel. Uma vez dentro da empresa você pode copiar seu conteúdo ou modificá-lo. Uma observação importante: apesar de o símbolo ser o mesmo que na multiplicação, o operador ‘* (multiplicação) não é o mesmo operador que o (referência de ponteiros). Para começar o primeiro é binário, e o segundo é unário pré-fixado.

[/toggle]
[toggle title=”Primeiro exemplo com Ponteiros”]

Abaixo encontram-se dois exemplos do uso de ponteiros:

#include 
main ()
{
int num,valor;
int *p;
num=55;
p=# /* Pega o endereco de num */
valor=*p; /* Valor e igualado a num de uma maneira indireta */
printf ("nn%dn",valor);
printf ("Endereco para onde o ponteiro aponta: %pn",p);
printf ("Valor da variavel apontada: %dnn",*p);
system("pause");
}

Programa 32 no C

[/toggle]
[toggle title=”Segundo exemplo com Ponteiros”]

Segundo exemplo:

#include 
main ()
{
int num,*p;
num=55;
p=# /* Pega o endereco de num */
printf ("nValor inicial: %dn",num);
*p=100; /* Muda o valor de num de uma maneira indireta */
printf ("nValor final: %dn",num);
}

Programa 33 no C

[/toggle]
[toggle title=”Operações aritméticas com Ponteiros”]

Acima , o primeiro exemplo mostra o funcionamento dos ponteiros, no primeiro exemplo, o código ‘%p utilizado na função ‘printf() indica à função que ela deve exibir um endereço. Podemos fazer algumas operações aritméticas com os ponteiros. A primeira, e a mais simples, é igualar dois ponteiros. Se temos dois ponteiros p1 p2 podemos igualá-los fazendo p1=p2. Repare que estamos fazendo com que p1 aponte para o mesmo lugar que p2. Se quisermos que a variável apontada por p1 tenha o mesmo conteúdo da variável apontada por p2 devemos fazer *p1=*p2. Basicamente, depois de aprender a utilizar os dois operadores (*) fica fácil entender operações com ponteiros. As próximas operações, também muito utilizadas, são o incremento e o decremento. Quando incrementamos um ponteiro ele passa a apontar para o próximo valor do mesmo tipo para o qual o ponteiro aponta. Isto é, se temos um ponteiro para um inteiro e o incrementamos ele passa a apontar para o próximo inteiro. Esta é mais uma razão pela qual o compilador precisa saber o tipo de um ponteiro: se você incrementa um ponteiro char* ele anda 1 byte na memória e se você incrementa um ponteiro double* ele anda 8 bytes na memória. O decremento funciona da mesma forma. Supondo que é um ponteiro, as operações são escritas como:

p++;
p--;

Lembre-se que estamos a falar de operações com ponteiros e não de operações com o conteúdo das variáveis para as quais os ponteiros apontam. Por exemplo, para incrementar o conteúdo da variável apontada pelo ponteiro p, faz-se:

(*p)++;

Outras operações aritméticas úteis são a soma e subtração de inteiros com ponteiros. Vamos supor que você queira incrementar um ponteiro de 15. Basta fazer:

p=p+15; ou p+=15;

E se você pretender utilizar o conteúdo do ponteiro, mas 15 posições á frente:

*(p+15);

A subtração funciona da mesma forma. Uma outra operação, às vezes útil, é a comparação entre dois ponteiros. Mas que informação recebemos quando comparamos dois ponteiros?

Bem, em primeiro lugar, podemos saber se os dois ponteiros são iguais ou diferentes (== !=). No caso de operações do tipo ><>= <= estamos a comparar qual dos ponteiro aponta para uma posição mais alta na memória. Então uma comparação entre ponteiros pode dizer-nos qual dos dois está mais á frente na memória. A comparação entre dois ponteiros escreve-se como a comparação entre outras duas variáveis quaisquer:

p1>p2

Existem também operações que não podemos efetuar num ponteiro. Não podemos dividir ou multiplicar ponteiros, adicionar dois ponteiros, adicionar ou subtrair floats ou double s de ponteiros.

[/toggle]

Gostou do tutorial? Então deixe um comentário abaixo!

Anúncios