Home > Tecnologia > Informática > Programação > C++ > Como usar apontadores em C / C++

Como usar apontadores em C / C++

Uma das dores de cabeça para alguns estudantes de programação é compreender o funcionamento dos apontadores em C / C++. Para já, é sempre bom lembrar que tudo o que se passa num computador, passa-se na memória. Os programa são executados na memória e os dados também são tratados na memória. Estes podem estar gravados em disco, ou noutro dispositivo de armazenamento, mas para um programa tratar estes dados, eles vão ter que ir para a memória RAM do computador.

Já o código máquina do processador utiliza registos para “apontar” endereços de memória, quer para executar código, quer para aceder a dados. Quando programamos em C / C++, as nossas variáveis também são guardadas em memória. Porém, maioria das vezes, trabalhamos com as variáveis sem nos termos que preocupar com isso pois, internamente, o compilador vai sempre tratar de definir e alocar endereços de memória para as guardar.

Neste artigo vamos falar apenas numa introdução simples ao uso de apontadores. Em artigos próximos irei continuar este tema como outros exemplos mais elaborados.

Vamos então começar com uma abordagem simples e um exemplo básico de um troço de código em C:

    int i = 5;
    printf("O valor de i é %d", i);

Internamente, o compilador terá sempre que alocar um endereço de memória para a variável “i”. Isto torna-se mais evidente quando queremos escrever um programa que permita solicitar a um utilizador para introduzir um número:

    int i;
    printf("Introduza um valor para i: ");
    scanf("%d", &i);
    printf("O valor de i é %d", i);

Repare que no comando “scanf”, introduzimos “&i”. O símbolo “&” indica ao compilador que queremos passar o endereço de “i” e não o seu valor. Sem esta notação, o comando “scanf” iria receber o valor da variável (que nem sequer foi inicializado) e não o seu endereço! Logo, o comando não iria saber qual o endereço de memória onde colocar o valor introduzido pelo utilizador.



Vamos agora ver outro exemplo complete de um programa que gera um número aleatório. Claro que este exemplo podia ser feito numa função ou até simplificado, mas o intuito é percebermos como lidar com apontadores quando passamos argumentos para um procedimento ou função:

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

void aleatorio(int *k) {
    srand(time(NULL));     // Para gerar números aleatórios
    int j = rand() % 10;   // Obtém um número de 0 a 9
    *k = j;
}

int main() {
    int i;
    aleatorio(&i);
    printf("i = %d", i);
    return 0;
}

Neste programa, o procedimento “aleatorio” recebe um argumento declarado como “int *k” (linha 5). Isto quer dizer que o procedimento pretende receber um apontador para o endereço de memória de uma variável do tipo “int” e não um valor inteiro. Repare também como estamos a guardar o valor no argumento – linha 8. Se fizéssemos apenas “k = j” iríamos ter um erro! Repare que “k” é um apontador e contem o endereço de memória da variável que foi passada para o método “aleatorio”, logo não podemos alterar esse endereço com um valor qualquer de uma variável “j”! Por isso, ao indicar “*k = j” estamos a dizer ao compilador que queremos que o valor de “j” seja guardado no endereço de memória apontado por “k”! Finalmente, a chamada do procedimento na linha 13. Temos que indicar que queremos passar o endereço de “i”.

Agora, e se quiséssemos declarar logo “i” como um apontador? Vejamos como fica a função “main”:

int main() {
    int *i;
    aleatorio(i);
    printf("i = %d", *i);
    return 0;
}

Neste caso, já não precisamos de usar “&i” quando passamos a variável para o procedimento “aleatorio” (linha 3) pois esta já é um apontador! Porém, e tome nota, para escrever o valor da variável (linha 4) não podemos colocar apenas “i” pois, nesse caso, iria exibir no ecrã o endereço de memória da variável e não o seu valor! Temos, por isso, que escrever “*i” para indicarmos que queremos que seja exibido o valor da variável e não o seu endereço.



Por fim, outra questão que pode trazer alguma confusão é com os arrays! Por omissão, os arrays são sempre tratados no C / C++ como apontadores. Mais acima vimos, por exemplo, que para pedir um valor inteiro ao utilizador, tivemos que colocar “&i” no “scanf”. E se quisermos pedir uma string num array de chars?

    char nome[60];
    printf("Introduza um nome: ");
    scanf("%59s", nome);
    printf("O nome é %s", nome);

Repare que não foi necessário colocar “&nome” no “scanf”, pois “nome” já vai ser um apontador para o primeiro elemento do array de chars. Mas também não é necessário colocar “*nome” no “printf”, pois neste caso, o comando também vai precisar de receber o endereço do primeiro elemento do array para poder escrever o seu conteúdo.

Continue a ler mais no próximo artigo: “Funções malloc e realloc em C / C++“.

Este artigo foi escrito de acordo com a antiga grafia.

About Carlos Santos

Frequência em mestrado de Engenharia Electrotécnica e de Computadores. Programador freelancer: Websites, Aplicações Web (JAVA e PHP), J2SE/J2EE, C/C++ e Android. Explicador e formador em informática, matemática e electrotecnia. Formação presencial ou remota através de Skype e Team Viewer. Interesses: Música, áudio, vídeo, ciência, astronomia e mitologia.

Leave a Reply

Your email address will not be published and it is optional.