Upload
duongthu
View
229
Download
0
Embed Size (px)
Citation preview
1
IAED, 2012/2013
Ponteiros e Tabelas
K&R: Capitulo 5
IAED, 2012/2013 2
Ponteiros e Tabelas
• Ponteiros e endereços • Ponteiros e argumentos de funções • Ponteiros e tabelas • Alocação dinâmica de memória • Aritmética de ponteiros • Tabelas de ponteiros e ponteiros para ponteiros • Tabelas multi-dimensionais • Inicialização de tabelas de ponteiros • Argumentos da linha de comandos • Ponteiros para funções
2
IAED, 2012/2013 3
Ponteiros em C
=
IAED, 2012/2013 4
Ponteiros e Endereços
• Na memória do computador cada posição é referenciada por um endereço, atribuído de forma sequencial
• Posições adjacentes têm endereços consecutivos
3245434
3245435
3245436
3245437
3
IAED, 2012/2013 5
Ponteiros e Endereços
• Um ponteiro é uma variável que contém o endereço de outra variável
3245434
3245435
3245436
3245437
3245438
3245439
3245440
3245441
3245442
3245443
‘a’
3245435 char c = ‘a’; char *ptr = &c;
aponta
declaração de um ponteiro inicializo ptr com
o endereço de c
IAED, 2012/2013 6
Um ponteiro em C
é um endereço de memória
IAED, 2012/2013 6
4
IAED, 2012/2013 7
Um ponteiro em C
é um endereço de memória
IAED, 2012/2013 7
IAED, 2012/2013 8
Ponteiros e Endereços
• Declaração de um ponteiro para tipo <tipo>
• Exemplos
<tipo> *<variável>;
char *cptr; /* ponteiro para caracter */
int *iptr; /* ponteiro para inteiro */
double *dptr; /* ponteiro para double */
5
IAED, 2012/2013 9
Ponteiros e Endereços
• Operador & aplicado a x representa o endereço de x
#include <stdio.h>
int main() {
int y, x = 1;
int *px;
px = &x; y = *px;
*px = 0;
printf("%d %d\n", x, y);
return 0;
}
IAED, 2012/2013 10
Ponteiros e Endereços
• Operador * aplicado a px representa o conteúdo da posição de memória apontada por px
#include <stdio.h>
int main() {
int y, x = 1;
int *px;
px = &x;
y = *px; *px = 0; printf("%d %d\n", x, y);
return 0;
}
6
IAED, 2012/2013
Utilizações do * (asterisco)
• Declaração do ponteiro
– x é um ponteiro para um inteiro
• Conteúdo da posição de memória apontada pelo ponteiro
– o valor 4 é atribuído ao conteúdo da posição de memória apontada por x
11
int *x;
*x = 4;
IAED, 2012/2013 12
Utilização de Ponteiros
• O valor de retorno de uma função pode ser um ponteiro
• O argumento de uma função pode ser um ponteiro
• Prioridade de & e * é superior à dos operadores aritméticos – y = *px + 1 funciona como esperado – ++*px incrementa o valor de x – (*px)++ (os parênteses são necessários)
int *xpto();
int abcd(char *a, int *b);
7
IAED, 2012/2013 13
Passagem de Parâmetros para Funções
• Em C os parâmetros são passados por valor
• Não funciona como necessário !
void swap(int a, int b) { int aux;
aux = a;
a = b;
b = aux; }
IAED, 2012/2013 14
Passagem de Parâmetros para Funções
• Passagem por referência consegue-se enviando ponteiros
• Chamada deverá ser swap(&x, &y)
void swap(int *a, int *b) { int aux;
aux = *a;
*a = *b;
*b = aux; }
8
IAED, 2012/2013 15
Ponteiros e Tabelas
• Em C existe uma relação entre ponteiros e tabelas
• a é um ponteiro para a primeira posição da tabela
#include <stdio.h>
int main() {
int a[6] = {1, 2, 3, 4, 5, 6 };
int *pa = a;
printf("%d %d %d\n", a[2], *(a+2), *(pa+2));
return 0; }
IAED, 2012/2013 16
Ponteiros e Tabelas
• A declaração int *p1; declara o mesmo que int p2[]; – p1 pode ser alterado – p2 não pode ser alterado – int p2[]; só pode ser utilizado em certos casos
• A declaração int p3[100]; declara uma tabela com 100 inteiros e aloca memória na quantidade necessária – p3 não pode ser alterado
• A declaração char *text; não aloca qualquer memória – no entanto char *text = "ola"; aloca;
9
IAED, 2012/2013 17
Ponteiros e Tabelas
• Qual a diferença entre as duas declarações seguintes ?
• Ambas alocam 4 bytes e copiam para essa posição de memória a sequência de caracteres 'o','l','a','\0'
• Em ambos os casos é possível modificar o conteúdo da memória alocada
• Não é possível alterar o valor de t1, ou seja não é possível pôr t1 a apontar para outra posição de memória
• É possível alterar o valor de t2
char t1[] = "ola"; char *t2 = "ola";
IAED, 2012/2013 18
Ponteiros e Tabelas
• Exemplo: cópia de strings void strcpy(char *s, char *t)
{
int i = 0
while ((s[i] = t[i]) != ’\0’)
i++;
}
void strcpy(char *s, char *t) {
while ((*s = *t) != ’\0’) {
s++;
t++;
}
}
10
IAED, 2012/2013 19
Ponteiros e Tabelas
• Exemplo: cópia de strings void strcpy(char *s, char *t) {
while ((*s = *t) != ’\0’) {
s++;
t++;
}
}
void strcpy(char *s, char *t)
{
while ((*s++ = *t++));
}
IAED, 2012/2013 20
Ponteiro Nulo / Endereço Zero
• Ponteiro especial para representar o endereço 0
• Definido em stdlib.h – Necessário #include <stdlib.h>
• Utilizado para indicar situações especiais
• Na realidade NULL == 0
int *ptr = NULL;
11
IAED, 2012/2013 21
Alocação Dinâmica de Memória
• Alocação estática
– Memória alocada durante o scope da variável – Não é possível libertar quando não necessária – Não é possivel utilizar fora do scope
• Solução: alocação dinâmica !
int tab[100];
IAED, 2012/2013 22
Alocação Dinâmica de Memória
• Função malloc
• Recebe como argumento o número de bytes – Tipo size_t representa uma dimensão em bytes
• Devolve um ponteiro (endereço) para o primeiro byte do bloco de memória contígua alocada (mas não inicializada) – void * indica um ponteiro para um tipo não especificado – permite utilização com qualquer tipo de dados – posteriormente faz-se conversão para o tipo correcto por type cast
void *malloc(size_t size);
int *tab; tab = (int *) malloc(4*100);
12
IAED, 2012/2013 23
Alocação Dinâmica de Memória
• Função malloc
• Recebe como argumento o número de bytes – Tipo size_t representa uma dimensão em bytes
• Devolve um ponteiro (endereço) para o primeiro byte do bloco de memória contígua alocada (mas não inicializada) – void * indica um ponteiro para um tipo não especificado – permite utilização com qualquer tipo de dados – posteriormente faz-se conversão para o tipo correcto por type cast
void *malloc(size_t size);
int *tab; tab = (int *) malloc(sizeof(int)*100);
IAED, 2012/2013 24
Alocação Dinâmica de Memória
• malloc retorna NULL caso não seja possível alocar a memória pedida
• Verificar sempre o resultado do pedido de memória
int *pvector
pvector = (int *) malloc(sizeof(int)* VEC_SIZE);
if (pvector == NULL){
fprintf(stderr, “Erro: falta de memória\n”);
exit(-1); }
13
IAED, 2012/2013 25
Alocação Dinâmica de Memória
• Memória válida desde o ponto em que é alocada até ser libertada ou até o programa terminar
• Exemplo: alocar memória para uma string e copiá-la
char *strsav(char *s)
{ char *d;
d = (char *) malloc(sizeof(char)*(strlen(s)+1));
strcpy(d, s);
return d; }
IAED, 2012/2013 26
Alocação Dinâmica de Memória
• Libertação de memória é efectuada com a função free
• Recebe como argumento o ponteiro para a primeira posição do bloco de memória contígua a libertar
• Não devolve nada
• Tanto malloc como free estão definidas em stdlib.h – Necessário #include <stdlib.h>
void free(void *ptr);
14
IAED, 2012/2013 27
Alocação Dinâmica de Memória
• Função realloc
• Recebe ponteiro ptr para bloco de memória antigo e dimensão size do novo bloco de memória
• Devolve ponteiro para novo bloco de memória • Copia valores do bloco antigo para o novo
– Se novo fôr mais pequeno, só copia até caber – Se novo fôr maior, copia tudo e deixa o resto sem ser inicializado
void *realloc(void *ptr, size_t size);
IAED, 2012/2013 28
Alocação Dinâmica de Memória
• Função calloc
• Aloca memória para uma tabela de nmemb elementos, cada um com dimensão size em bytes
• Devolve ponteiro para a tabela alocada • A mesma coisa que malloc(nmemb*size); • A memória alocada é inicializada toda a 0 (zeros)
void *calloc(size_t nmemb, size_t size);
15
IAED, 2012/2013 29
Aritmética de Endereços
• É possível efectuar + e - com ponteiros
int x = 10; int *px = &x;
x px
IAED, 2012/2013 30
Aritmética de Endereços
• É possível efectuar + e - com ponteiros
• Incrementa/decrementa na dimensão do tipo para o qual aponta – sizeof(int) neste caso
int x = 10; int *px = &x;
px++; x px
16
IAED, 2012/2013 31
Tabelas de Ponteiros
• É possível definir tabelas em que cada elemento é um ponteiro
• Neste caso definimos uma tabela com 100 elementos, em que cada elemento é um ponteiro para int
• tabptr também é um ponteiro
int *tabptr[100];
IAED, 2012/2013 32
Tabelas Multi-Dimensionais
• A declaração int x[NROWS][NCOLS] declara uma matriz – Aloca espaço NROWS*NCOLS de inteiros
• É equivalente a int *x[NROWS] – Aloca espaço NROWS de ponteiros para inteiros – Permite que linhas tenham tamanhos diferentes
• Elemento na linha i e coluna j é x[i][j]
• Na prática, ponteiros para tabelas são mais usados • Qualquer número de dimensões pode ser usado • Primeira dimensão pode não ser especificada
17
IAED, 2012/2013 33
Inicialização de Tabelas de Ponteiros
char *month_name(int n)
{ static char *name[] = {
"Illegal month",
"January", "February", "March",
"April", "May", "June",
"July", "August", "September", "October", "November", "December"
};
return (n < 1 || n > 12) ? name[0] : name[n];
}
IAED, 2012/2013 34
Ponteiros para Ponteiros
• É possível declarar um ponteiro para um ponteiro
#include <stdio.h>
int main() {
int x = 10;
int *px = &x;
int **ppx = &px; printf("%d %d %d\n", x, *px, **ppx);
return 0;
}
18
IAED, 2012/2013 35
Argumentos da Linha de Comandos • argc - argument count - número de parametros
• argv - argument values - tabela de strings com os argumentos – argv[0] é o nome do programa – argv[i] é i-ésimo argumento
• Programa "echo" • $ echo hello world hello world
3 int main(int argc, char *argv[]) { int i;
for(i=1; i < argc; i++)
printf("%s ", argv[i]);
printf("\n %d", argc);
return 0;
}
IAED, 2012/2013 36
Ponteiros para Funções
• É possível ter ponteiros para funções • O nome de uma função é um ponteiro para essa função
int soma(int a, int b) { return a+b; }
int main() {
int (*ptr)(int, int);
ptr = soma;
printf("%d\n", (*ptr)(3,4)); return 0; }
19
IAED, 2012/2013 37
• Base: base • Primeira posição livre: top • # de posições alocadas: size
• # de posições ocupadas: top-base
• Está cheia quando: top-base == size
Exemplo: Pilha Dinâmica de Inteiros
4
2 base
size
top
IAED, 2012/2013 38
Exemplo: Pilha Dinâmica de Inteiros
#include <stdio.h>
#include <stdlib.h>
#define INITSIZE 3
static int *base; static int *top; static int size;
20
IAED, 2012/2013 39
• Base: base • Primeira posição livre: top • # de posições alocadas: size
• # de posições ocupadas: top-base
• Está cheia quando: top-base == size
Exemplo: Pilha Dinâmica de Inteiros
base top
size
IAED, 2012/2013 40
Exemplo: Pilha Dinâmica de Inteiros
void init() { size = INITSIZE; base = (int*) malloc(size*sizeof(int)); top = base; }
21
IAED, 2012/2013 41
• Base: base • Primeira posição livre: top • # de posições alocadas: size
• # de posições ocupadas: top-base
• Está cheia quando: top-base == size
Exemplo: Pilha Dinâmica de Inteiros
2 base top
size
top
push(2);
IAED, 2012/2013 42
• Base: base • Primeira posição livre: top • # de posições alocadas: size
• # de posições ocupadas: top-base
• Está cheia quando: top-base == size
Exemplo: Pilha Dinâmica de Inteiros
4
2 base
size
top
push(4);
top
22
IAED, 2012/2013 43
• Base: base • Primeira posição livre: top • # de posições alocadas: size
• # de posições ocupadas: top-base
• Está cheia quando: top-base == size
Exemplo: Pilha Dinâmica de Inteiros
6
4
2 base
size
push(6);
top
top
IAED, 2012/2013 44
• Base: base • Primeira posição livre: top • # de posições alocadas: size
• # de posições ocupadas: top-base
• Está cheia quando: top-base == size
Exemplo: Pilha Dinâmica de Inteiros
6
4
2 base
size
push(8);
top
23
IAED, 2012/2013 45
• Quando está cheia, duplica a dimensão: size = size * 2
• Aloca novo bloco de memória com o dobro da dimensão e copia elementos para lá
• Insere novo elemento
Exemplo: Pilha Dinâmica de Inteiros
8
6
4
2 base
size
push(8);
top
top
IAED, 2012/2013 46
Exemplo: Pilha Dinâmica de Inteiros
void push(int value) { if (top-base == size) increase_size();
*(top++) = value; }
24
IAED, 2012/2013 47
Exemplo: Pilha Dinâmica de Inteiros
void increase_size() { int *oldbase = base; int *pa, *pb;
size *= 2; base = (int*) malloc(size * sizeof(int)); for (pa = oldbase, pb = base; pa < top; ) *(pb++) = *(pa++);
free(oldbase);
top += base - oldbase; /* top = pb; */ }
IAED, 2012/2013 48
• Base: base • Primeira posição livre: top • # de posições alocadas: size
• # de posições ocupadas: top-base
• Está cheia quando: top-base == size
Exemplo: Pilha Dinâmica de Inteiros
8
6
4
2 base
size
pop();
top
top
25
IAED, 2012/2013 49
Exemplo: Pilha Dinâmica de Inteiros
int pop() { if (!is_empty()) return *(--top); else
return -1;
}
int is_empty() { return top == base; }
IAED, 2012/2013 50
O que é um ponteiro em C ?
IAED, 2012/2013 50
26
IAED, 2012/2013 51
Um ponteiro em C
é um endereço de memória
IAED, 2012/2013 51
IAED, 2012/2013 52
O que é um ponteiro em C ?
IAED, 2012/2013 52
27
IAED, 2012/2013 53
Um ponteiro em C
é um endereço de memória
IAED, 2012/2013 53
IAED, 2012/2013 54
Apple II
IAED, 2012/2013 54