Code::Blocks e ponteiros


Em todos os tutoriais usarei a IDE Code::Blocks. É mil vezes melhor do que o popular Dev C/C++ e é igualmente gratuito, além de ter a enorme vantagem de ser “cross-platform”, ou seja, você pode instalar ele em mais de um sistema operacional. No caso do Code::Blocks ele pode ser instalado no Windows, no Linux e no Mac OS X.

Link para download: http://www.codeblocks.org/downloads

Não vou dar detalhes sobre a instalação, talvez em um post futuro. Também está no projeto uma explicação de como usar o debugger, que no Code::Blocks funciona efetivamente.

Criando um projeto no Code::Blocks:

Clique no botão New e em seguida em Project…:

Em seguida aparece uma janela para a seleção do tipo de projeto, na maioria dos tutoriais usaremos “Console Application”, selecione esta opção e clique em Go. Também pretendo fazer tutoriais sobre a biblioteca gráfica Gtk+.

Um assistente para criação do projeto irá abrir, clique em Next. Na tela de seleção de linguagem, selecione C. No próximo passo coloque o nome do projeto e escolha o local onde os arquivos serão salvos, recomendo criar uma pasta só para o projeto.

Na próxima tela deixa as opções como na imagem:

Clique em Finish e pronto, o projeto está criado e já com um arquivo main.c.

Ponteiros

Como quase todo tutorial aqui vai ser na linguagem C, é de fundamental importância o pleno entendimento dos ponteiros, tão detestados pelos iniciantes, e tão fundamentais.

Como o próprio nome diz, um ponteiro é um tipo de dado que aponta para uma posição da memória, ou seja, a informação que ele guarda é um endereço de memória, não um dado em si.

Falando grosseiramente sobre arquitetura de computadores, cada posição de memória tem um número que a identifica, por exemplo, se você está trabalhando com uma memória de 1 gb, a primeira posição será a 1 e a última será a 1.073.741.824 (muita coisa hein?), e é exatamente essa identificação que um ponteiro guarda.

Notação:

Um ponteiro pode ser de qualquer tipo, abaixo estão algumas declarações de ponteiros:

int *p;
float *f;
char *s;

Essa é a forma de declarar um ponteiro, que não tem nada haver com a forma de se usar um ponteiro. Vamos supor que declaramos um ponteiro para inteiro (int *p).

Observação: Em C quando declaramos uma variável, seja ela de que tipo for, ela não é zerada, o que significa que a posição de memória que foi alocada para ela tem o que chamamos de lixo, uma informação que não foi o seu programa que criou, simplesmente foi largada na memória por outro programa.

O operador & e o operador *:

Quando você aplica o operador & sobre uma variável, você recebe o endereço de memória onde ela está armazenada, vejamos o seguinte trecho de código:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>
 
int main(void)
{
    int *p=NULL; /* Declaramos p inicialmente apontando para nada */
    int a=10;
 
    printf("Valor do ponteiro: %p",p); /* Aqui o valor do ponteiro será NULL */
    printf("\nEndereço de a: %p",&a);
 
    p = &a; /* O ponteiro p recebe o endereço de memória de a */
 
    printf("\nValor do ponteiro: %p",p);
    printf("\nConteudo do ponteiro: %d",*p); /* O operador * recupera a informação armazenada no endereço de memória apontado por p */
 
    return 0;
}

Como comentado no código, o operador * recupera a informação armazenada no endereço de memória apontado por p. No exemplo acima, p aponta para a, que armazena o valor 10, portando *p será 10.

Agora vamos analisar o seguinte código:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <stdio.h>
 
int main(void)
{
    int *p=NULL; /* Declaramos p inicialmente apontando para nada */
    int a=100,b=200,c=300,d=400,e=500;
 
    p = &a; /* p aponta para a */
    printf("\n*p = %d",*p);
 
    *p = c; /* O conteudo de p recebe c, mas como p aponta para a, a recebe c */
    printf("\n*p = %d",*p);
    printf("\n a = %d\n",a);
 
    p = &b; /* p aponta para b */
    printf("\n*p = %d",*p);
 
    *p = d; /* O conteudo de p recebe d, mas como p aponta para b, b recebe c */
    printf("\n*p = %d",*p);
    printf("\n b = %d\n",b);
 
    p = &e; /* p aponta para e */
    printf("\n*p = %d",*p);
 
    *p = 600; /* O conteudo de p recebe o valor 600, mas como p aponta para e, e recebe c */
    printf("\n*p = %d",*p);
    printf("\n e = %d\n",e);
 
    e = 700; /* e recebe 700, como p aponta para e, *p será 700 */
    printf("\n*p = %d",*p);
    return 0;
}

Na linha 8 p recebe o endereço de a, ou seja, p aponta para a:

Na linha 11 o conteúdo de p recebe c, mas como p aponta para a, a recebe c:

Na linha 15 p recebe o endereço de b, ou seja, p aponta para b:

Na linha 18 o conteúdo de p recebe d, mas como p aponta para b, b recebe d:

Na linha 22 p recebe o endereço de e, ou seja, p aponta para e:

Na linha 25 o conteúdo de p recebe o valor 600, mas como p aponta para e, e recebe o valor 600:

Na linha 29 e recebe o valor 700, portanto *p será 700 também.

Observação: Veja como o modo de declarar ponteiros é diferente do modo de usá-los. Quando declaramos um ponteiro, se fizermos int *p = 2341, significa que o ponteiro está apontando para a posição 2341 da memória, mas se fizermos *p = 2341 em outra parte, significa que o conteúdo de p recebe 2341.

Curiosidade: Quando um vetor é declarado, por exemplo, int a[10], “a” contem o endereço do primeiro elemento do vetor, logo a == &a[0].

Em breve postarei algumas aplicações práticas de ponteiros, como listas encadeadas.

Tags: ,

Leave a Reply