Buscar

Ponteiro em C: Definição e Operações

Prévia do material em texto

PONTEIROS
Definição: um ponteiro é uma variável que contém o endereço de uma outra variável. 
Toda variável declarada em um programa tem um endereço de memória alocado para 
si e o número de posições de memória alocado depende do seu tipo (como já foi visto). 
Ponteiros podem apontar (receber o endereço) para variáveis de qualquer um dos tipos 
disponíveis na linguagem. 
Variáveis possuem nomes, endereços e conteúdos. Quando se conhece o nome da 
variável, pode-se acessá-la através do nome. Eventualmente, possuímos apenas o endereço 
de uma variável e, para acessá-la, precisamos utilizar os ponteiros. 
Ponteiros são importantes para: alocação dinâmica de memória, passagem de 
parâmetros para funções, entre outras.
Declaração: se uma variável vai conter um ponteiro (endereço), ela deve ser declarada 
como tal. Uma declaração de ponteiro consiste no tipo base, um * e o nome da variável.
Forma Geral: < tipo > * < nome_do_ponteiro > ;
Exemplo: int valor, *ponteiro_valor;
No exemplo, ponteiro_valor será usado para apontar para uma variável do tipo 
inteiro. Um ponteiro não deve apontar para uma variável que não seja do seu tipo base.
O operador &: O operador endereço & é usado para indicar o endereço de uma variável. 
Sempre que desejamos fazer um ponteiro apontar (receber o endereço) para uma variável 
temos que usar este operador.
Ex.: ...
 ponteiro_valor = &valor;
 ...
No exemplo acima, a variável ponteiro ponteiro_valor recebe o endereço da variável 
valor, ou seja, após esta atribuição o ponteiro ponteiro_valor estará apontando para a 
variável valor. 
Para se chegar ao conteúdo realmente armazenado na variável valor, através de seu 
ponteiro, deve-se usar agora o operador * , que significa: o valor no endereço.
Ex.: ...
 int valor, valor_aux, *ponteiro_valor;
 
 valor = 10;
 ponteiro_valor = &valor;
 valor_aux = *ponteiro_valor;
 printf(“ Valor armazenado: %d \n”, valor_aux);
 /* ou printf(“ Valor armazenado: %d \n”, *ponteiro_valor); */
Como ponteiros são variáveis (que ao invés de conter valores, contêm endereços) 
podemos atribuir ponteiros para ponteiros como fazemos com variáveis comuns.
Ex.: ...
 int valor, *ponteiro_valor, *ponteiro_novo;
 valor = 10;
 ponteiro_valor = &valor;
 ponteiro_novo = ponteiro_valor;
 printf(“Valor armazenado: %d \n”, *ponteiro_novo);
 ...
No exemplo acima, ponteiro_novo passa a apontar para o mesmo endereço para o 
qual aponta ponteiro_valor (recebe o endereço que está dentro de ponteiro_valor).
RESUMO:
Declaração, operador &, operador * e atribuição.
--» a05a.c
Operações Aritméticas com Ponteiros: É possível realizar adição e subtração sobre 
ponteiros buscando-se endereços de memória (apontando-se para valores) que estejam acima 
(adição) ou abaixo (subtração) do endereço atual contido no ponteiro. 
Por exemplo, para um ponteiro de nome p, a operação p++ faz com que p passe a 
apontar para o próximo elemento, qualquer que seja o tipo de objeto para o qual p aponta. Já 
p += i (p = p + i), faz com que p passe a apontar i elementos além (acima) do objeto para 
o qual p aponta atualmente. 
Ex.: main ()
 {
 int *ponteiro, vetor_inteiros[4] = {0, 10, 20, 30};
 
 ponteiro = &vetor_inteiros[0];
 ponteiro+= 2; /* igual a: ponteiro = &vetor_inteiros[2]; */
 printf(“Valor apontado: %d \n”, *ponteiro);
 ...
 }
No exemplo, ponteiro aponta para o primeiro elemento do vetor vetor_inteiros. A 
soma ponteiro+= 2 faz com que ponteiro passe a apontar 2 elementos acima do valor atual 
(no caso para o valor inteiro 20).
É IMPORTANTE RESSALTAR QUE O COMPILADOR C AUTOMATICAMENTE RECONHECE O TIPO 
BÁSICO DO PONTEIRO E PULA A QUANTIDADE DE ENDEREÇOS RESPECTIVOS. NO EXEMPLO, A SOMA 
CAUSOU UM SALTO DE 4 OU 8 ENDEREÇOS ( TAMANHO EM BYTES DE UM INT).
--» a05b.c
Inicialização de Ponteiros: Como ponteiros também são variáveis, muitas vezes é preciso 
inicializá-los a fim de evitar valores iniciais inconsistentes (lixos já existentes na memória). 
Para ponteiros costuma-se usar a constante NULL, predefinida pela linguagem, que contém 
o valor zero.
Ex.: ...
 int *ponteiro_val = NULL;
 ...
Vetores e Ponteiros: A forma de acesso a vetores, vista anteriormente, usava um índice 
(vetores unidimensionais) para acessar cada elemento do vetor. Entretanto, COMO O NOME DE 
UM VETOR É, NA REALIDADE, UM PONTEIRO PARA O PRIMEIRO ELEMENTO DO VETOR DECLARADO 
(ARMAZENA O ENDEREÇO DO INÍCIO DOS DADOS DO VETOR NA MEMÓRIA), pode-se usar este nome 
(ponteiro) como uma forma de acesso alternativa e mais ágil que a usual (via índices).
Ex.: Para acessar o primeiro elemento de um vetor de nome valores:
 elem = valores[0]; ou elem = *valores;
 Para acessar o segundo elemento:
 elem = valores[1]; ou elem = *(valores + 1);
Pode-se acessar também cada elemento de um vetor através de um ponteiro auxiliar 
como foi visto na seção anterior ( exemplo a05b.c). Importante: NÃO se deve executar 
operações aritméticas que alterem o valor no nome do vetor, pois, caso contrário, o endereço 
de início do vetor na memória será perdido. Exemplo: NÃO SE FAZ valores = valores + 2. 
Para este tipo de situação, usa-se um ponteiro auxiliar.
RESUMO:
Aritmética de ponteiros, inicialização de ponteiros, e vetores e ponteiros.
--» a05c.c
 Exercícios resolvidos sobre ponteiros:
1. Escrever um programa para alocar dinamicamente um vetor de inteiros, preencher este vetor com valores 
lidos do teclado e, por último, escrever o vetor.
#include <stdio.h>
#include <conio.h>
#include <alloc.h>
#include <stdlib.h>
void main()
{
int tam, * pt_aux, * vet;
int i;
 char aux [ 10];
printf ( "Entre com o numero de elementos do vetor: ");
 gets ( aux);
tam = atoi ( aux);
vet = ( int *) malloc ( tam * sizeof ( int));
pt_aux = vet;
for ( i = 0; i < tam; i ++) {
printf ( "Entre com o valor do elemento %d: ", i);
 gets ( aux);
* pt_aux ++ = atoi ( aux);
}
printf ( "\n");
 pt_aux = vet;
for ( i = 0; i < tam; i ++) {
printf ( "O valor do elemento %d eh: %d\n", i, * pt_aux +
+);
}
free ( vet);
 getch ( );
}
Completar este programa ( sempre usando ponteiros) para informar ao usuário:
• o maior valor no vetor;
• o menor valor no vetor;
• o valor médio armazenado no vetor;
• e o número de valores negativos no vetor.
2. Escrever um programa para imprimir, do último para o primeiro, cada um dos elementos do vetor do 
exemplo a05b.c, através do mesmo ponteiro auxiliar pt.
3. Escrever um programa para ler uma frase qualquer do teclado e imprimir, esta mesma frase, um caracter 
por vez.
#include <stdio.h>
#include <conio.h>
#include <alloc.h>
#include <stdlib.h>
void main()
{
char frase [ 255], * aux;
printf ( "Entre com uma frase qualquer: ");
gets ( frase);
aux = frase;
while ( * aux) printf ( "%c", * aux ++);
printf ( "\n");
 getch ( );
}
Completar este programa ( sempre usando ponteiros) para:
• imprimir a frase ao contrário;
• contar o número de espaços em branco na frase.
Exercícios propostos sobre ponteiros:
1. Escrever um programa para imprimir as matrizes declaradas abaixo utilizando ponteiros.
#include <stdio.h>
main ( )
{
int vetor [ 5] = { 0, 1, 2, 3, 4};
int matriz [ 5] [ 5] = {
 0, 0, 0, 0, 0,
 1, 1, 1, 1, 1,
 2, 2, 2, 2, 2,
 3, 3, 3, 3, 3,
 4, 4, 4, 4, 4};
char string [ 10] = "BICAMPEAO";
}
2. Escrever um programa para alocar dinamicamenteuma área de memória para N 
doubles, preencher esta área com valores lidos do teclado e, por último, 
proporcionar uma consulta aos dados gravados. A consulta deve receber um número, 
que corresponde a uma das posições da área alocada, e o valor double armazenado 
naquela posição deve ser apresentado ao usuário. O programa deve fazer uma 
consistência no número informado, correspondente à posição, e apresentar uma 
mensagem de erro se ele estiver aquém ou além dos limites da área de memória.
3. Escrever um programa para alocar uma área de memória para armazenar 3 valores 
float e 3 caracteres, preencher esta área com dados provenientes do teclado e, por 
último, apresentá-los do último até o primeiro, isto é, de maneira inversa àquela do 
armazenamento.
4. Escrever um programa que recebe um nome completo e, posteriormente, armazena-o 
numa área de memória alocada dinamicamente. O tamanho desta área deve ser 
exatamente o necessário para armazenar corretamente o nome informado. Por 
último, o nome armazenado na área alocada deve ser impresso (usar %s no printf).
5. Escrever um programa que recebe o nome de uma disciplina do curso de Engenharia 
e um caracter avulso. O programa deve informar o endereço da primeira ocorrência 
deste caracter no nome da disciplina (usar %x no printf). Igualmente, deve ser dada 
uma notificação caso o caracter não seja encontrado.

Outros materiais