M´
etodos Computacionais em F´
ısica I - Ponteiros
5
Ponteiros para variáveis
Observemos o exemplo seguinte:
#include <stdio.h>
Resultado:
int main()
pi vale 0x22efc4 e (*pi) vale 0
{ int i = 0;
agora pi vale 0x22efc4 e (*pi) vale 3
int j;
agora pi vale 0x22efc1 e (*pi) vale 7
int *pi = NULL;
pi = &i;
printf("pi vale %p e (*pi) vale %d\n", pi, *pi);
(*pi) = 3;
printf("pi vale %p e (*pi) vale %d\n", pi, *pi);
j=7;
pi = &j;
printf("pi vale %p e (*pi) vale %d\n", pi, *pi);
return 0;
}
M´
etodos Computacionais em F´
ısica I - Ponteiros
6
Ponteiros como argumento de funções
❒ Em C os argumentos de funções são passados por valor. O que fazer se
precisamos alterar um argumento?
Ex.: Uma função que troca os valores de duas variáveis.
❒ Os ponteiros permitem o acesso direto à memória. Dando um ponteiro
para uma variável como argumemto de uma função nos permite mudar
o valor desta variável.
M´
etodos Computacionais em F´
ısica I - Ponteiros
7
m pd p
0x22efc1
5 0x22efc1 0x22efc1
int main(){
double m;
double * pd = NULL;
m = 5;
pd = &m;
mudaMassa(pd);
}
void mudaMassa(double *p){
*p = 8;
return
}
M´
etodos Computacionais em F´
ısica I - Ponteiros
8
void troca( int *i, int *j);
int main()
{
int a=2,b=5;
int *pb=&b;
printf("a=%d b=%d\n",a,b);
troca(&a,pb);
printf("a=%d b=%d\n",a,b);
return 0;
}
void troca( int *i, int *j)
{
int temp=*i;
*i = *j;
*j = temp;
return;
}
M´
etodos Computacionais em F´
ısica I - Ponteiros
9
❒ Observe que os parâmetros formais da função são ponteiros. Os
parâmetros reais são ponteiros ou endereços das variáveis
❒ Para acessarmos os valores das variáveis dentro da função devemos
usar o operador *
M´
etodos Computacionais em F´
ısica I - Ponteiros
10
Ponteiros e arrays
❒ A implementação de arrays em C está bastante interligada com a de
ponteiros, visando facilitar a manipulação dos arrays.
❒ Podemos utilizar a sintaxe normal para fazer um ponteiro apontar para
um elemento de um array:
double *pa, *pb;
double v[5]={1.,3.,7.,4.,6.};
pa = &v[2]; // pa aponta para o elemento 3 de v
pb = &v[4]; // pb aponta para o elemento 5 de v
*pa = 5.; // O valor do elemento 5 de v agora e’ 5
...
❒ Mas podemos utilizar a sintaxe especial para ponteiros e arrays, junto
com as operações para ponteiros
❒ Podemos fazer um ponteiro p apontar para o inı́cio de um array v
M´
etodos Computacionais em F´
ısica I - Ponteiros
11
fazendo p = v;. É a única situação em que o nome do array tem
sentido sem os colchetes. Equivale a fazer p = &v[0];
❒ Podemos usar a sintaxe de arrays com o ponteiro:
Se fizermos p = v; podemos acessar o i-ésimo elemento de v
fazendo p[i]
Mas se fizermos p = &v[3];, p[2] apontará para v[5]!
❒ Podemos fazer algumas operações com ponteiros. Sejam p e q dois
ponteiros:
❒ Somar ou subtrair um inteiro de um ponteiro:
p=p-2; q++; *(p+2) = 3.0;
❒ Subtrair dois ponteiros:
p = p-q; Retorna um inteiro: n´ umero de elementos entre p e q
❒ Comparar dois ponteiros do mesmo tipo:
if(p == q) ...; if(p > q)...;
while( p !=q )... ; ...; if( p != 0 )...
M´
etodos Computacionais em F´
ısica I - Ponteiros
12
❒ Não existe ponteiro para array. O mesmo ponteiro que aponta para
uma variável double pode apontar para um array de doubles. Na
realidade ele aponta para um elemento do array
M´
etodos Computacionais em F´
ısica I - Ponteiros
14
Ponteiros para funções
❒ Às vezes precisamos trabalhar com uma função genérica, num trecho
de programa que se aplica a qualquer função de determinado tipo. Para
isto a linguagem C implementa o ponteiro para funço˜es.
❒ Sua declaração inclui o protótipo completo da função:
// Ponteiro para uma funcao que recebe um double
// e retorna um double
double (*f)( double x );
❒ Atenção aos parêntesis em (*f). São necessários pois parêntesis tem
precedência maior. double *f(double) seria um função que
retorna um ponteiro para double!
M´
etodos Computacionais em F´
ısica I - Ponteiros
15
#include <stdio.h>
#include <math.h>
#define PI 3.141592
void tabela( double (*f)( double ), double xmin, double xmax, double dx )
{ double x;
for(x=xmin;x<=xmax;x+=dx) printf("%f %f\n",x,f(x));
}
int main()
{ double (*g)( double );
printf("x(rad) seno(x)\n");
tabela(sin,0.,PI,PI/5);
printf("x(rad) cos(x)\n");
tabela(cos,0.,PI,PI/5);
g = exp;
printf("x exp(x)\n");
tabela( g,0.0, 2.0, 0.2);
return 0;
}
M´
etodos Computacionais em F´
ısica I - Ponteiros
16
Alocação dinâmica de memória
❒ Quando definimos um array devemos dar a sua dimensão (alocação
estática, ou em tempo de compilação)
❒ Em diversas aplicações precisamos trabalhar com arrays de dimensão
variável.Ex.:
1)Programa que calcula a média das notas de uma turma
2)Array de caracteres para armazenar nomes de pessoas
3)Array com as propriedades dos fragmentos criados numa explosão
(número diferente a cada explosão)
❒ Solução simples: Definimos um array de dimensão bem grande e só
usamos o que for necessário
– Desperdı́cio de memória.
– E se ocorrer um caso com mais elementos do que o previsto?
❒ Alocaç˜
ao dinˆ
amica de mem´
oria: A exata quantidade de memória
M´
etodos Computacionais em F´
ısica I - Ponteiros
17
necessária pode ser alocada no momento em que for necessária. O
limite é apenas a memória disponı́vel no computador. Esta memória
pode ( e deve) ser liberada quando não for mais necessária.
❒ Usa o fato de que podemos trabalhar com ponteiros como se fossem
arrays
❒ seja dim a dimensão de um array de doubles que queremos alocar
(pode ser calculado num passo anterior do programa , ou lido do
teclado...). Para alocarmos um array dinamicamente:
1. Incluimos o arquivo de cabecalho correspondente:
#include <stdlib.h>
2. Determinamos a quantidade de memória a ser alocada:
size_t tamanho;
tamanho = sizeof( double ) * dim;
size t é um tipo inteiro adequado para o tamanho do tipo de
dados (ex., double) num certo sistema
M´
etodos Computacionais em F´
ısica I - Ponteiros
18
sizeof é um operador que retorna o tamanho daquele tipo de
dado no sistema
3. Usamos a função malloc para reservar a memória necessária. Ela
retorna um ponteiro genérico para o inı́cio da área reservada.
Devemos convertê-lo (casting) para o tipo que estamos trabalhando
double *p1=NULL;
...
p1= (double *) malloc(tamanho);
if( p1==NULL) { Erro! }
Se não for possı́vel alocar a memória, malloc retorna NULL.
Devemos sempre testar se isto ocorreu.
4. Usamos p normalmente como um array de doubles de dimensão
dim.
5. Quando não precisarmos mais deste array devemos liberar a
memória alocada:
M´
etodos Computacionais em F´
ısica I - Ponteiros
19
free(p1);
p1 = NULL;
Vejamos um exemplo completo
/* Exemplo de alocacao dinamica de memoria
A dimensao do vetor e’ lida em tempo de execucao
*/
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
int main()
{ double *p1=NULL, *p2=NULL;
size_t tamanho;
int dim;
int i;
printf("Entre com a dimensao dos vetores\n");
scanf("%d",&dim);
tamanho = sizeof( double ) * dim;
p1= (double *) malloc(tamanho);
p2= (double *) malloc(tamanho);
M´
etodos Computacionais em F´
ısica I - Ponteiros
20
if( p1==NULL || p2 == NULL ){
printf("Erro: Nao foi possivel alicar a memoria requerida\n");
return 1;
}
printf("Entre com as componentes do vetor\n");
for( i=0;i<dim;i++) scanf("%lf",(p1+i));
printf("\n As componentes sao \n");
for( i=0;i<dim;i++) printf("%f ",p1[i]);
M´
etodos Computacionais em F´
ısica I - Ponteiros
23
Funções que retornam ponteiros
M´
etodos Computacionais em F´
ısica I - Ponteiros
24
Tarefa 9
Escreva um programa que ordene os dados contidos no arquivo
amostra2.dat. Seu programa deve:
• Usar alocação dinâmica para criar um vetor que guarde todos os dados
do arquivo de entrada.
• Fazer o ordenamento através de uma função do tipo void.
M´
etodos Computacionais em F´
ısica I - Ponteiros
25