32
Aula 17: Ponteiros e Alocac¸˜ ao Dinˆ amica em C Fernanda Passos Universidade Federal Fluminense Programac¸˜ ao de Computadores IV Fernanda Passos (UFF) Ponteiros e Aloca¸ ao Dinˆ amica Programa¸ ao de Computadores IV 1 / 32

Aula 17: Ponteiros e Alocação Dinâmica em C - ic.uff.brfernanda/2016-1/progIV/aulas/aula17.pdf · Fernanda Passos (UFF) Ponteiros e Aloca¸c˜ao Dinˆamica Programa¸c˜ao de Computadores

  • Upload
    doandan

  • View
    212

  • Download
    0

Embed Size (px)

Citation preview

Aula 17: Ponteiros e Alocacao Dinamica em C

Fernanda Passos

Universidade Federal Fluminense

Programacao de Computadores IV

Fernanda Passos (UFF) Ponteiros e Alocacao Dinamica Programacao de Computadores IV 1 / 32

Agenda

1 Revisao e Contexto

2 Definicao de Ponteiros

3 Operacoes com Ponteiros

4 Alocacao Dinamica de Memoria

Fernanda Passos (UFF) Ponteiros e Alocacao Dinamica Programacao de Computadores IV 2 / 32

Agenda

1 Revisao e Contexto

2 Definicao de Ponteiros

3 Operacoes com Ponteiros

4 Alocacao Dinamica de Memoria

Fernanda Passos (UFF) Ponteiros e Alocacao Dinamica Programacao de Computadores IV 3 / 32

Aula Anterior:

Manipulacao de arquivos:I Vimos o conceito de arquivos e streams em C.

F Stream: fluxo de dados sequenciais.F Arquivo: dispositivo associado ao stream.

I Como abrir e fechar: associar e desassociar um stream a um arquivo.I Como escrever e ler de um stream de texto.I Como identificar fim de arquivo.

Fernanda Passos (UFF) Ponteiros e Alocacao Dinamica Programacao de Computadores IV 4 / 32

Foco da Aula de Hoje

Ponteiro:Definicao em relacao a memoria do computador.Declaracao e operadores relacionados a ponteiros.Operacoes com ponteiros.

Alocacao dinamica:Funcoes de alocacao dinamica.Como usa-las.

Objetivos:Entender o conceito de ponteiros em memoria.Aprender como alocar dinamicamente memoria usando funcoes pre-definidas em C.

Fernanda Passos (UFF) Ponteiros e Alocacao Dinamica Programacao de Computadores IV 5 / 32

Agenda

1 Revisao e Contexto

2 Definicao de Ponteiros

3 Operacoes com Ponteiros

4 Alocacao Dinamica de Memoria

Fernanda Passos (UFF) Ponteiros e Alocacao Dinamica Programacao de Computadores IV 6 / 32

Introducao: Memoria

A memoria principal e o local onde o computador guarda a grande maioria das variaveisalocadas no programa.O processador precisa acessar a memoria frequentemente para ter acesso a esses dados.O processador acessa a memoria atraves de enderecos.I O endereco indica onde um valor esta na memoria.

Organizacao de uma memoria de tamanho Tmem:

1024 1025 1026 1027 10280 Tmem-1

... ...Dados:

Endereços:

Fernanda Passos (UFF) Ponteiros e Alocacao Dinamica Programacao de Computadores IV 7 / 32

Introducao: Memoria (II)

Considere o seguinte codigo:1 int main(int argc, char * argv[]){2 char letra = ’b’;3 return(0);4 }

Neste exemplo, uma variavel do tipo char e alocada.I Ela ocupara uma posicao de memoria e, portanto, tera um endereco (por ex.: 1024).

1024 1025 1026 1027 10280 Tmem-1

... ...b

I A variavel ’letra’ fica associada ao endereco de memoria 1024.I O comando &letra retorna 1024.

Fernanda Passos (UFF) Ponteiros e Alocacao Dinamica Programacao de Computadores IV 8 / 32

Ponteiro

Definicao de Ponteiro:E uma variavel que contem um endereco de memoria.

Esse endereco e normalmente a posicao de uma outra variavel na memoria.Dizemos que uma variavel que contem um endereco aponta para outra variavel.

1024 1025 1026 1027 10280 Tmem-1

... ...Dados:

Endereços:

1027

Fernanda Passos (UFF) Ponteiros e Alocacao Dinamica Programacao de Computadores IV 9 / 32

Declaracao de um Ponteiro

Um ponteiro precisa ser declarado como tal.Para isso, usamos um tipo base, um * e um nome para o ponteiro.

Declaracao de Ponteiro:tipo * nome;

O tipo base e o tipo da variavel para que o ponteiro aponta.Exemplo de uma declaracao de ponteiro para o tipo char:

1 int main(int argc, char * argv[]){2 char letra = ’b’;3 char * ponteiro_para_letra;4 return(0);5 }

Fernanda Passos (UFF) Ponteiros e Alocacao Dinamica Programacao de Computadores IV 10 / 32

Agenda

1 Revisao e Contexto

2 Definicao de Ponteiros

3 Operacoes com Ponteiros

4 Alocacao Dinamica de Memoria

Fernanda Passos (UFF) Ponteiros e Alocacao Dinamica Programacao de Computadores IV 11 / 32

Operadores de Ponteiros

Existem dois: & e *.I Ambos sao operadores unarios.

Operador &: devolve o endereco na memoria de seu operando.I Exemplo: ptr letra = &letra;I Le-se “ptr letra recebe o endereco de letra”.I Suponha que letra tem o valor ’b’ e esta no endereco 1027.I Entao, ptr letra tem o valor 1027.

1024 1025 1026 1027 10280 Tmem-1

... ...Dados:

Endereços:

1027

letraptr_letra

b

Fernanda Passos (UFF) Ponteiros e Alocacao Dinamica Programacao de Computadores IV 12 / 32

Operadores de Ponteiros (II)

Operador *: devolve o valor da variavel localizada no endereco indicado pelo seuoperando.I Geralmente usado sobre variavel declarada como ponteiro.I Exemplo: m = *ptr letra;I Le-se “m recebe o valor do endereco de ptr letra”.I Se ptr letra guarda o endereco 1027 da variavel letra, entao m tera o valor de letra.I Como no endereco ha o valor ’b’, logo, m tera o valor ’b’.

1024 1025 1026 1027 10280 Tmem-1

... ...Dados:

Endereços:

1027

letraptr_letra

b

*

Fernanda Passos (UFF) Ponteiros e Alocacao Dinamica Programacao de Computadores IV 13 / 32

Operadores de Ponteiros: Exemplo 1

1 #include <stdio.h>2

3 int main(int argc, char * argv[]){4 int * ptr;5 int a = 100;6 int b;7

8 ptr = &a;9 printf("Valor de a: %d\n", a);

10 printf("Endereco de a: %p\n", &a);11 printf("Valor de ptr_a: %p\n", ptr);12 printf("Endereco de ptr_a: %p\n", &ptr);13 b = *ptr;14 printf("Valor de b: %d\n", b);15 printf("Endereco de b: %p\n", &b);16 return(0);17 }

Exemplo de saıda:

Valor de a: 100Endereco de a: 0x7fffa380f600Valor de ptr_a: 0x7fffa380f600Endereco de ptr_a: 0x7fffa380f608Valor de b: 100Endereco de b: 0x7fffa380f604

Fernanda Passos (UFF) Ponteiros e Alocacao Dinamica Programacao de Computadores IV 14 / 32

Atribuicao com Ponteiros

Podemos fazer atribuicoes entre ponteiros.I Um ponteiro pode ser atribuıdo a outro.

1 #include <stdio.h>2

3 int main(int argc, char * argv[]){4 int x = 0;5 int *p1, *p2;6

7 p1 = &x;8 p2 = p1;9

10 printf("p1: %p e p2: %p\n", p1, p2); /* escreve o endereco de x,11 nao seu valor! */12 return(0);13 }

Fernanda Passos (UFF) Ponteiros e Alocacao Dinamica Programacao de Computadores IV 15 / 32

Aritmetica de Ponteiros

Outro tipo de expressao e a aritmetica de ponteiros.Apenas as operacoes de adicao e subtracao sao permitidas.Agora, o tipo base do ponteiro faz toda a diferenca!I As operacoes de aritmeticas sao realizadas de acordo com o tamanho em bytes do tipo.

Exemplo para um ponteiro p1 declarado como int:p1++;

Neste exemplo, o valor de p1 e incrementado, mas no valor de sizeof(int) = 4 (bytes).Se o endereco inicial era 2000, ele passara a ser 2004.I E nao 2001!

Fernanda Passos (UFF) Ponteiros e Alocacao Dinamica Programacao de Computadores IV 16 / 32

Aritmetica de Ponteiros: Exemplo 2Acessar elementos de um vetor usando aritmetica de ponteiros:

1 #include <stdio.h>2

3 int main(int argc, char * argv[]){4 int i, vet[10];5 int *p;6

7 for(i = 0; i<10; i++){8 vet[i] = i;9 }

10 p = vet; // atribui o ponteito p ao vetor.11 for(i = 0; i<10; i++){12 printf("%d ", *(p++));13 // Outra forma:14 //printf("%d ", *(p + i));15 }16 printf("\n");17

18 return(0);19 }

Fernanda Passos (UFF) Ponteiros e Alocacao Dinamica Programacao de Computadores IV 17 / 32

Inicializacao de Ponteiros

Algumas vezes, e necessario inicializar um ponteiro.Existe uma palavra reservada para isso: NULL.Um ponteiro, entao, pode ser inicializado com o valor NULL.Exemplo de trecho:

1 int * p = NULL;2 char * s;3

4 s = NULL;

Fernanda Passos (UFF) Ponteiros e Alocacao Dinamica Programacao de Computadores IV 18 / 32

Ponteiro de Ponteiros (Indirecao Multipla)

E possıvel criar ponteiro de ponteiros.Tambem chamado de indirecao multipla.E um ponteiro apontando para outro ponteiro que aponta para o valor final.

Fernanda Passos (UFF) Ponteiros e Alocacao Dinamica Programacao de Computadores IV 19 / 32

Ponteiro de Ponteiros: Declaracao

Neste caso, devemos declarar da seguinte maneira:I tipo **ponteiro;

O acesso do valor e feito por: **ponteiro;

1 #include <stdio.h>2

3 int main(int argc, char * argv[]){4 int x, *p, **q;5

6 x = 10;7 p = &x;8 q = &p;9

10 printf("%d\n", **q); // Imprime o valor de x.11

12 return(0);13 }

Fernanda Passos (UFF) Ponteiros e Alocacao Dinamica Programacao de Computadores IV 20 / 32

Agenda

1 Revisao e Contexto

2 Definicao de Ponteiros

3 Operacoes com Ponteiros

4 Alocacao Dinamica de Memoria

Fernanda Passos (UFF) Ponteiros e Alocacao Dinamica Programacao de Computadores IV 21 / 32

Alocacao Dinamica de Memoria

Quando declaramos uma variavel ou um vetor/matriz usando ”tipo nome”, estamosdeclarando estaticamente.Uma declaracao estatica significa que uma regiao de memoria e alocada durante acompilacao.I Deste modo, a regiao de memoria alocada e inalteravel.I Uma consequencia e que nao se pode mudar seu tamanho depois de alocada.

Em C, e possıvel alocar memoria dinamicamente.I i.e., em tempo de execucao.I Isto permite algumas facilidades, como alocar um tamanho de vetor/matriz de acordo com o

seu real tamanho.F Veremos, a seguir, como podemos fazer isso.

Fernanda Passos (UFF) Ponteiros e Alocacao Dinamica Programacao de Computadores IV 22 / 32

Funcoes de Alocacao Dinamica de Memoria

Em C, existem funcoes capazes de alocar memoria dinamicamente.Estas funcoes estao disponıveis em stdlib.h.I Portanto, stdlib.h deve ser incluıda no codigo fonte do programa.

Sao elas:

Funcao Significadomalloc() Aloca regiao de memoria com tamanho especificado.calloc() Mesmo que malloc(), mas inicializa com 0.realloc() Altera o tamanho da regiao de memoria previamente alocada.free() Libera regiao de memoria previamente alocada.

Veremos aqui apenas malloc() e free().

Fernanda Passos (UFF) Ponteiros e Alocacao Dinamica Programacao de Computadores IV 23 / 32

Funcao malloc

Assinatura da funcao malloc:void *malloc(size_t size);

A funcao retorna um ponteiro para void.I void e um tipo vazio.I Serve para indicar que a funcao retorna ponteiro para qualquer tipo.I Devemos usar casting ao alocar memoria de um tipo especıfico.

Repare que, agora, o uso de ponteiro e imprescindıvel.O unico parametro da funcao malloc e o tamanho em bytes.I E conveniente o uso do sizeof(tipo).

Fernanda Passos (UFF) Ponteiros e Alocacao Dinamica Programacao de Computadores IV 24 / 32

Funcao free

Assinatura da funcao free:void free(void *ptr);

A funcao nao retorna nada (procedimento).O unico parametro da funcao free e o ponteiro da memoria a ser liberada.I Comando para desalocar memoria.

Importante: um malloc sempre deve ter um free associado!I Memoria alocada consome espaco de armazenamento.I Assim que terminar o uso, ela deve ser desalocada.

Fernanda Passos (UFF) Ponteiros e Alocacao Dinamica Programacao de Computadores IV 25 / 32

Funcao malloc e free: Exemplo 3Alocar dinamicamente um inteiro:

1 #include <stdio.h>2 #include <stdlib.h>3

4 int main(int argc, char * argv[]){5 int * inteiro = NULL;6

7 // Aloca um inteiro dinamicamente.8 // Uso de cast de ponteiro para inteiro.9 // O tamanho em bytes e sizeof(int).

10 inteiro = (int *) malloc(sizeof(int));11 // Atribui um valor ao inteiro alocado dinamicamente.12 *inteiro = 5;13 // Escreve seu valor.14 printf("valor do inteiro: %d\n", *inteiro);15

16 free(inteiro);17 return(0);18 }

Fernanda Passos (UFF) Ponteiros e Alocacao Dinamica Programacao de Computadores IV 26 / 32

Alocacao Dinamica de Vetores/Matrizes

Uma boa utilidade da alocacao dinamica e para alocar vetores e matrizes.Util no caso de alocar vetores/matrizes de tamanho dinamico.Por exemplo:I Pedimos para que o usuario entre com o tamanho do vetor (ou vamos le-lo);I ao se conhecer esse tamanho (durante a execucao do programa), seu programa alocara

dinamicamente a memoria necessaria para armazena-lo.Desta forma, iremos alocar exatamente a quantidade de memoria necessaria.I Nao e mais necessario superestimar o tamanho do vetor como era feito na alocacao estatica.

Fernanda Passos (UFF) Ponteiros e Alocacao Dinamica Programacao de Computadores IV 27 / 32

Alocacao Dinamica de Vetores: Exemplo 4Alocar dinamicamente um vetor de float de tamanho indicado pelo usuario:

1 #include <stdio.h>2 #include <stdlib.h>3 int main(int argc, char * argv[]){4 float * vet_float = NULL;5 int tamanho_vet, i;67 do{8 printf("Digite o tamanho do vetor a ser alocado: ");9 scanf("%d", &tamanho_vet);

10 } while(tamanho_vet <= 0 || tamanho_vet > 1000);1112 vet_float = (float *) malloc(tamanho_vet*sizeof(float));13 for(i=0; i<tamanho_vet; i++)14 vet_float[i] = i / 2.0;1516 printf("Vetor de tamanho %d:\n", tamanho_vet);17 for(i=0; i<tamanho_vet; i++)18 printf("%.1f ", vet_float[i]);19 printf("\n");20 free(vet_float);21 return(0);22 }

Fernanda Passos (UFF) Ponteiros e Alocacao Dinamica Programacao de Computadores IV 28 / 32

Alocacao Dinamica de Matrizes

Para alocar matrizes, o procedimento e um pouco diferente.Uma matriz e uma especie de vetor de vetores.I Lembrando que usamos ponteiro para identificar um vetor.

Sendo assim, para alocar matrizes dinamicamente, temos que:1 alocar dinamicamente um vetor de ponteiros para o tipo da matriz, usando:

tipo **ptr ptr;ptr ptr = (tipo **) malloc(m*sizeof(tipo *));

2 para cada posicao do vetor de ponteiros, alocar um novo vetor.for(i=0; i<m; i++)

ptr ptr[i] = (tipo *) malloc(n*sizeof(tipo));I O tamanho do vetor de ponteiros corresponde ao numero de linhas da matriz m.I O tamanho de cada novo vetor corresponde ao numero de colunas da matriz n.

Fernanda Passos (UFF) Ponteiros e Alocacao Dinamica Programacao de Computadores IV 29 / 32

Alocacao Dinamica de Matrizes (II)

Para desalocar uma matriz o processo e inverso:1 para cada posicao do vetor de ponteiros, liberar o vetor usando:

for(i=0; i<m; i++)free(ptr ptr[i]);

2 por ultimo, liberar o vetor de ponteiros.free(ptr ptr);

Fernanda Passos (UFF) Ponteiros e Alocacao Dinamica Programacao de Computadores IV 30 / 32

Alocacao Dinamica de Matrizes: Exemplo 5Alocar dinamicamente uma matriz m × n, onde m e n sao dados.

1 #include <stdio.h>2 #include <stdlib.h>3 int main(int argc, char * argv[]){4 int ** mat = NULL;5 int m, n, i, j;6

7 do{8 printf("Digite as dimensoes da matriz: ");9 scanf("%d %d", &m, &n);

10 } while(m <= 0 || n<=0 || m > 1000 || n > 1000);11

12 // Alocacao de matriz:13 mat = (int **) malloc(m*sizeof(int *));14 for(i=0; i<m; i++)15 mat[i] = (int *) malloc(n*sizeof(int));16

17 // continua...

Fernanda Passos (UFF) Ponteiros e Alocacao Dinamica Programacao de Computadores IV 31 / 32

Alocacao Dinamica de Matrizes: Exemplo 5 (cont.)18 mat = (int **) malloc(m*sizeof(int *));19 for(i=0; i<m; i++)20 mat[i] = (int *) malloc(n*sizeof(int));21

22 for(i=0; i<m; i++)23 for(j=0; j<n; j++)24 mat[i][j] = i*m + j;25 for(i=0; i<m; i++){26 for(j=0; j<n; j++)27 printf("%4d ", mat[i][j]);28 printf("\n");29 }30

31 // Libera a matriz:32 for(i=0; i<m; i++) free(mat[i]);33 free(mat);34

35 return(0);36 }

Fernanda Passos (UFF) Ponteiros e Alocacao Dinamica Programacao de Computadores IV 32 / 32