Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
Algoritmos Estruturados e
Linguagem de Programação Estruturada
Ponteiros em C
Parte I – Conceitos Básicos
1Introdução
Uma das mais poderosas características oferecidas pela linguagem C é o uso de
ponteiros. Ponteiros proporcionam o acesso a variáveis sem referenciá-las diretamente, ou
seja, por meio do endereço de memória das variáveis.
Algumas razões para o uso de ponteiros:
• fornecem maneiras pelas quais as funções em C podem modificar os argumentos que
recebem;
• usá-los no lugar de vetores, matrizes e strings para aumentar a efeciência;
• para alocação dinâmica de memória;
• para criar estruturas de dados complexas, como listas encadeadas, pilhas, árvores, etc.
Além dos ponteiros serem uma das características mais fortes de C, também é a mais
perigosa. O uso incorreto de ponteiros provoca desde erros difíceis de serem encontrados
até uma queda no sistema.
Memória do Computador
Endereço Conteúdo
1000 1003
1001
1002
1003
1004
1005
1006
... ...
1
Assim, usado um ponteiro é possível acessar o conteúdo de memória de uma variável
sem referenciá-la diretamente, o que é conhecido como endereçamento indireto.
Além do endereçamento indireto, um ponteiro em C também pode ser utilizado em um
programa para alocar memória em tempo de execução, o que é conhecido como alocação
dinâmica de memória.
Essas duas possibilidades de utilização de ponteiros serão abordadas com detalhes no
decorrer deste texto.
tipo-de-dado *nome;
onde:
tipo-de-dado: é um tipo de dado válido em C;
nome: é um identificador válido para a variável ponteiro. É o asterisco (*) que faz o
compilador saber que a variável não vai armazenar um valor, mas sim um endereço de
memória que contenha um valor do tipo especificado.
Exemplos de declarações:
Os ponteiros p, temp e p2 ainda não foram inicializados (como toda variável do C que
é apenas declarada). Isso significa que eles apontam para um lugar indefinido da memória.
Esse lugar pode estar, por exemplo, na porção da memória reservada ao sistema operacional
do computador. Usar o ponteiro nessas circunstâncias pode levar a um travamento do
computador. Desse modo, um ponteiro deve ser inicializado (apontado para algum lugar
conhecido) antes de ser usado.
Para atribuir um valor a um ponteiro recém-criado a fim de inicializá-lo, bastaria
igualá-lo a um valor de memória. Mas, como saber a posição na memória de uma variável do
programa? Seria muito difícil saber o endereço de cada variável usada em um programa,
mesmo porque esses endereços são determinados pelo compilador (em tempo de compilação)
e realocados na execução. Pode-se então deixar que o compilador faça esse trabalho. Para
saber o endereço de uma variável basta usar o operador &. Por exemplo:
int cont;
int *p;
cont = 10;
p = &cont; /* obtém o endereço de cont e atribui para p */
Nesse exemplo declarou-se uma variável do tipo inteiro cont e uma variável ponteiro
para inteiro p. Em seguida atribuiu-se o valor 10 para cont. A expressão &cont fornece o
endereço da variável cont, o qual é armazenado em p. Nesse momento, p está inicializado e
pode, então, ser utilizado.
2
Deve-se observar no exemplo anterior que o valor de cont não foi alterado, ou seja,
cont continua com o conteúdo 10. Pode-se, então, alterar o valor de cont usando p. Para tanto
usa-se o operador *.
Considerando o exemplo anterior, no momento em que se executa a instrução:
p = &cont;
A expressão *p passa a ser equivalente à própria variável cont. Isso significa que,
pode-se alterar o valor de cont para 12, basta fazer:
*p = 12;
#include <stdio.h>
main()
{
int num, valor;
int *p;
num = 55;
p = # /* Obtém o endereço de num */
valor = *p; /* a variável valor recebe o mesmo valor de num de
maneira indireta */
printf("Valor = %d\n", valor);
printf("Endereco para onde o ponteiro aponta: %p\n", p);
printf("Valor da variavel apontada: %d\n", *p);
}
Deve-se observar que o código %p usado na função printf() indica que deve imprimir
um endereço (em hexadecimal).
#include <stdio.h>
main()
{
int num,*p;
num = 55;
p = # /* Obtém o endereço de num */
printf("Valor inicial: %d\n", num);
*p = 100; /* Altera o valor de num de maneira indireta */
printf("Valor final: %d\n", num);
}
3
4.1Atribuições com Ponteiros
Considerando dois ponteiros p1 e p2 pode-se atribuir o conteúdo de p1 a p2 fazendo
p1 = p2. A atribuição p1 = p2 faz com que p1 aponte para o mesmo endereço que p2. Deve-
se observar que se fosse necessário fazer com que a variável apontada por p1 tenha o mesmo
conteúdo da variável apontada por p2 o comando seria *p1=*p2.
Por exemplo, o programa seguinte exibe o endereço de memória de x (em
hexadecimal) por meio do ponteiro p2:
#include <stdio.h>
main()
{
int x;
int *p1, *p2;
p1 = &x;
p2 = p1; /* atribui p1 para p2 */
printf("%p %p %p",&x, p1, p2); /* imprime 3 vezes o endereço
de memória de x */
}
char *c = 3000;
Memória do Computador
Endereço Conteúdo
c 3000
c+1 3001
c+2 3002
c+3 3003
c+4 3004
c+5 3005
... ...
int *i = 3000;
Memória do Computador
Endereço Conteúdo
3000
i
3001
3002
i+1
3003
3004
i+2
3005
4
... ...
5
Supondo que p é um ponteiro, as operações são escritas como:
p++; /* ou p = p + 1 */
p--; /* ou p = p – 1 */
p = p + 5; /* ou p += 5 */
Mais uma vez vale lembrar que as operações são com os ponteiros e não com o
conteúdo das variáveis para as quais eles apontam. Por exemplo, para incrementar o conteúdo
da variável apontada pelo ponteiro p, faz-se:
(*p)++; /* ou *p += 1 ou *p = *p + 1 */
*(p+15)
Entretanto, existem operações que não podem ser realizadas com ponteiros. Por
exemplo, não se pode dividir ou multiplicar ponteiros, adicionar dois ponteiros, adicionar ou
subtrair valores do tipo float e double de ponteiros.
p1 > p2
6
5Exercícios de Fixação
1) Explique a diferença entre:
p++; (*p)++; *(p++);
#include <stdio.h>
main()
{
int y, *p, x;
y = 0;
p = &y;
x = *p;
x = 4;
(*p)++;
x--;
(*p) += x;
printf ("y = %d\n", y);
}