Ponteiros em C
Prof. Kariston Pereira
Adaptado de Material gentilmente fornecido pelo
Prof. Rui Tramontin (DCC/UDESC)
1
Índice
Introdução
Operações sobre Ponteiros
Exemplos
Ponteiros e Funções
Alocação Dinâmica em C
UDESC – Prof. Kariston Pereira
2
Introdução
Um ponteiro é uma variável cujo conteúdo é um
endereço de memória.
Normalmente, de outra variável.
Nesse caso, diz-se que o ponteiro aponta para a variável.
Devem ser associados e um tipo de dados, e são
declarados com um “*” antes do seu identificador:
int *ponteiro;
UDESC – Prof. Kariston Pereira
3
Operações sobre Ponteiros
Operadores para ponteiros:
& - retorna o endereço de uma variável.
* - retorna o conteúdo apontado pelo ponteiro.
int *ip;
int x;
ip = &x;
*ip = 100;
ip
x
UDESC – Prof. Kariston Pereira
100
4
Exemplo
int x = 1, y =
2;
int *ip;
x
1
3
y
2
1
ip
ip = &x;
y = *ip;
*ip = 3;
UDESC – Prof. Kariston Pereira
5
Contra-Exemplo
Ponteiros devem sempre ser inicializados.
int *ip;
Erro na execução!
*ip = 10;
Ponteiro não inicializado.
int *ip;
int x;
ip = &x;
*ip = 10;
Ok!
UDESC – Prof. Kariston Pereira
6
Ponteiros e Funções
Parâmetros de funções podem ser de
dois tipos:
Por valor
Por referência;
Ponteiros são usados na passagem por
referência.
UDESC – Prof. Kariston Pereira
7
Ponteiros e Funções
Exemplo:
Função para troca de valores entre duas variáveis:
swap(a, b);
void swap(int x, int y)
{
int temp;
temp = x;
x = y;
y = temp;
}
UDESC – Prof. Kariston Pereira
Não funciona!
•Parâmetros são
alocados na pilha;
•Desalocados no final
da execução.
8
Ponteiros e Funções
Exemplo:
Função para troca de valores entre duas variáveis:
swap(&a, &b);
void swap(int *x, int *y)
{
int temp;
temp = *x;
*x = *y;
*y = temp;
}
Funciona!
•Referências são passadas
como parâmetro.
•A modificação é feita
diretamente em a e b.
UDESC – Prof. Kariston Pereira
9
Alocação Dinâmica em C
UDESC – Prof. Kariston Pereira
10
Alocação Dinâmica em C
A memória alocada pelas funções de alocação
dinâmica é obtida do heap.
O heap é a região de memória livre que se encontra
entre o programa (com a área de armazenamento
permanente) e a pilha (stack).
A linguagem C possui duas funções básicas para
gerência de memória:
malloc(num de bytes) - aloca memória.
free(endereço) - libera memória
UDESC – Prof. Kariston Pereira
11
Função malloc()
Protótipo:
void *malloc(número_de_bytes);
Devolve um ponteiro do tipo void (sem tipo) para o
início (1º byte) da área de memória alocada.
Para isto deve ser utilizado sempre um typecasting.
x = (int *) malloc( sizeof(int) );
número_de_bytes é a quantidade de bytes
alocada.
UDESC – Prof. Kariston Pereira
12
Função free()
Protótipo:
void free( void *p );
Devolve memória previamente alocada apontada por
p.
A utilização de free() com um valor de ponteiro
qualquer poder ter resultados catastróficos.
A gerência de buracos no heap é responsabilidade do
sistema operacional.
UDESC – Prof. Kariston Pereira
13
Exemplo
#include <stdlib.h>
#include <stdio.h>
char
int
*a;
*b;
main ()
{
a = (char *) malloc(512);
// Aloca 512 bytes
b = (int *)
malloc(50*sizeof(int));
// Aloca espaço
// para 50 inteiros.
StackPointer
Topo da pilha
HeapPointer
Topo da área
alocável
50*int = 200 bytes
512 bytes
Variáveis
estáticas
Código objeto
a
b
100111010...
Constantes
free(a);
Sistema
Operacional
}
UDESC – Prof. Kariston Pereira
14
Aritmética de Ponteiros
UDESC – Prof. Kariston Pereira
15
Aritmética de Ponteiros
A linguagem C permite que se faça operações
aritméticas sobre ponteiros.
Oferece uma liberdade que nenhuma outra
linguagem de programação oferece (exceto
assemblers).
Isto é muito útil, porém é também muito perigoso!
Operações válidas com ponteiros: adição, subtração
e comparação.
São muito úteis com vetores.
UDESC – Prof. Kariston Pereira
16
Semântica da Aritmética de
Ponteiros
A aritmética de ponteiros leva em o tamanho
ocupado pelo tipo de dados apontado.
Sejam p um ponteiro para o tipo T, e i um valor
inteiro.
p + i é equivalente a:
endereço( p ) + i * sizeof( T )
p - i é equivalente a:
endereço( p ) - i * sizeof( T )
UDESC – Prof. Kariston Pereira
17
Ponteiros e Vetores
Vetores podem ser tratados como
ponteiros.
Aritmética de ponteiros é usada para
localizar elementos dentro de um vetor.
Dado um vetor A:
A[i] ≡ *( A + i )
UDESC – Prof. Kariston Pereira
18
Ponteiros e Vetores
Exemplo: int arr[10];
O tipo int ocupa 4 bytes na memória.
Assumindo que arr está no endereço 1000, temos:
UDESC – Prof. Kariston Pereira
19
Exemplos
UDESC – Prof. Kariston Pereira
20
Exemplo 1
int *aponta;
int valor1, valor2;
valor1 = 5;
aponta = &valor1;
valor2 = *aponta;
printf("%i\n", valor2);
UDESC – Prof. Kariston Pereira
21
Exemplo 2:
invertendo um vetor
int x[5] = {1, 2, 3, 4, 5};
int *left = x;
int *right = x + 4;
while(left < right)
{
int temp = *left;
*left = *right;
*right = temp;
left++;
right--;
}
UDESC – Prof. Kariston Pereira
22
int
p1
p2
p3
p4
*p1, *p2,2
*p3, *p4, x=0;
Exemplo
=
=
=
=
&x;
p1 + 1;
p2 + 4;
p3 - 5;
printf("%i\n",
printf("%i\n",
printf("%i\n",
printf("%i\n",
*p1);
*p2);
*p3);
*p4);
printf("%i\n",
printf("%i\n",
printf("%i\n",
printf("%i\n",
p1);
p2);
p3);
p4);
UDESC – Prof. Kariston Pereira
23
int
p1
p2
p3
p4
*p1, *p2,2
*p3, *p4, x=0;
Exemplo
=
=
=
=
&x;
p1 + 1;
p2 + 4;
p3 - 5;
printf("%i\n",
printf("%i\n",
printf("%i\n",
printf("%i\n",
*p1);
*p2);
*p3);
*p4);
//
//
//
//
0
printf("%i\n",
printf("%i\n",
printf("%i\n",
printf("%i\n",
p1);
p2);
p3);
p4);
//
//
//
//
1000
1004
1020
1000
“lixo”
“lixo”
0
UDESC – Prof. Kariston Pereira
24
char
char
char
int
nome[30] = "João da Silva";
*p1, *p2;
car;
i;
p1 = nome;
car = nome[3];
car = p1[0];
p2 = &nome[5];
printf("%s", p2);
p2 = p1;
p2 = p1 + 5;
printf("%s",(p1 + 5));
printf("%s",(p1 + 20));
for (i=0; i < strlen(nome); i++)
{
printf ("%c", nome[i]);
p2 = p1 + i;
printf ("%c", *p2);
}
UDESC – Prof. Kariston Pereira
25
char
char
char
int
nome[30] = "João da Silva";
*p1, *p2;
car;
i;
p1 = nome;
// nome é ponteiro. Mesmo que p1 = &nome[0].
car = nome[3];
// atribui 'o' a car.
car = p1[0];
// atribui 'J' a car.
p2 = &nome[5];
// p2 aponta para 6ª posição de nome ('d').
printf("%s", p2);
// imprime "da Silva".
p2 = p1;
// p2 aponta para o mesmo endereço de p1.
p2 = p1 + 5;
// equivalente a p2 = &nome[5].
printf("%s",(p1 + 5));
// imprime "da Silva".
printf("%s",(p1 + 20));
// imprime lixo! (cuidado).
for (i=0; i < strlen(nome); i++)
{
printf ("%c", nome[i]); // imprime 'J','o','ã',...
p2 = p1 + i; // p2 aponta para próximo caracter em nome.
printf ("%c", *p2);
// imprime 'J','o','ã',...
}
UDESC – Prof. Kariston Pereira
26