Ponteiros em C
Vamos começar a tratar hoje de um dos conceitos mais importantes (e provavelmente mais confusos) a se dominar em linguagem C: o conceito de Ponteiros.
O que é um ponteiro em C? Um ponteiro é uma variável especial que contém um endereço de memória armazenado, em vez de dados comuns. Esse endereço é, no geral, a posição na memória de uma outra variável. Desta forma, a variável que contém esse endereço aponta para a outra variável. Daí o nome “ponteiro“.
O domínio e o emprego dos ponteiros é extremamente importante para que seja possível programar com eficiência e desenvoltura em C. Eles são úteis em inúmeros contextos, como por exemplo no suporte à rotinas de alocação dinâmica de memória e na construção de ADTs – Abstract Data Types / Tipos de Dados Abstratos – como por exemplo pilhas, listas e filas.
A figura a seguir ilustra a ideia geral de funcionamento de um ponteiro:
Na figura, temos representados endereços na memória RAM do computador, e um conjunto de variáveis criadas nesses endereços. podemos ver que no endereço 5000 existe uma variável ponteiro, cujo conteúdo é o endereço de memória 5004 – ou seja, esse ponteiro aponta para a variável que está localizada no endereço 5004 da memória RAM.
Declarando ponteiros
Uma declaração de ponteiro consiste em um tipo, seguido do caractere * (chamado de “operador de indireção” ou de “dereferência“) e do nome que se deseja dar à variável. A sintaxe a seguir mostra a forma de se declarar um ponteiro:
tipo *nome;
O tipo, que pode ser qualquer um válido em C, define o tipo da variável que o ponteiro pode apontar. Por exemplo, suponha que se deseje criar um ponteiro de nome “ponteiro”, o qual aponte para uma variável do tipo float. Para tal, usamos a seguinte declaração:
float *ponteiro;
Essa declaração cria uma variável ponteiro que aponta para uma variável do tipo float – note que float é o tipo da variável apontada, e não do ponteiro em si.
Os ponteiros devem ser inicializados ao serem declarados ou por meio de uma declaração de atribuição posterior à sua declaração. Podemos inicializar um ponteiro com um endereço de memória, ou os valores 0 ou ainda NULL. Um ponteiro com o valor NULL não aponta para nenhum local. Apontar para 0 é equivalente a apontar para NULL, mas usar a palavra NULL deixa o código mais inteligível.
Operadores de Ponteiros
Em C há dois operadores especiais de ponteiros: os operadores * e &.
O operador & (operador de endereço) é um operador unário que permite retornar o endereço na memória de uma variável. Desta forma:
x = &valor;
esta declaração coloca na variável x o endereço de memória da variável valor, o qual não possui relação com o valor armazenado na variável. Podemos ler essa declaração como “x recebe o endereço da variável valor“.
O operador de indireção * é também um operador unário, e retorna o valor contido na variável localizada no endereço informado ao operador. Por exemplo, se a variável x contém o endereço da variável valor, e a variável valor armazena o valor (dado) 30, teremos:
y = *x;
essa declaração coloca o conteúdo da variável valor (30) na variável y. Assim, y conterá também o valor 30, pois 30 é o dado armazenado na posição de memória apontada por x. Podemos ler a declaração como “y recebe o valor armazenado no endereço apontado por x“.
Atribuição de ponteiros
Podemos atribuir um ponteiro a outro ponteiro, como fazemos com variáveis comuns. Veja o código a seguir:
#include <stdio.h> #include <stdlib.h> int main() { int a; a = 30; int *pont1, *pont2; pont1 = &a; pont2 = pont1; printf("Endereço de a: %p", pont2); return 0; }
Esse código irá mostrar na tela o endereço da variável a, mas não seu conteúdo armazenado (que é o valor 30). Tanto pont1 quanto pont2 são ponteiros que apontam para a variável a.
Para mostrar o endereço da variável a com a função printf() usamos o modificador de formato %p.
Se quisermos ver o conteúdo da variável, podemos usar a declaração a seguir, que mostra o conteúdo de a a partir do ponteiro pont2:
printf("Conteúdo de a: %d\n", *pont2);
Note o uso do operador *, para indicar que queremos o valor da variável apontada pelo ponteiro, e não seu endereço de memória.
Como retornar o endereço de uma variável
Podemos obter o endereço de uma variável (local da memória onde um dado está armazenado) usando o operador &, conforme vemos no código a seguir:
#include <stdio.h> #include <stdlib.h> #include <locale.h> int main() { setlocale(LC_ALL, " "); int num = 60; printf("Endereço da variável num: %p\n", &num); }
Ao executar esse programa, obteremos o endereço da variável num na memória RAM do computador.
Na próxima parte de nosso estudo sobre ponteiros vamos falar sobre Aritmética de Ponteiros.
Até!