Programação II Vetores e Alocação Dinâmica Bruno Feijó Dept. de Informática, PUC-Rio
Vetores (arrays) Vetor: estrutura de dados definindo um conjunto enumerável Exemplo: v = vetor de inteiros com 10 elementos int v[10]; Vetor pode ser inicializado int v[5] = 5, 10, 15, 20, 25 ; ou simplesmente: int v[] = 5, 10, 15, 20, 25 ; Acesso a cada elemento: V[0] é o primeiro elemento 5 V[1] é o segundo elemento 10... V[4] é o quinto elemento 25 V[5] errado! Invasão de memória!
Vetores (arrays) 144 Vetor é alocado em posições contíguas de memória Exemplo: v = vetor de inteiros com 10 elementos nome do vetor aponta para endereço inicial C permite aritmética de ponteiros Exemplo: v+0 : primeiro elemento de v... v+9 : último elemento de v Equivalência entre a sintaxe [] e a sintaxe +: *(v+i) é equivalente a v[i] (v+i) é equivalente a &v[i] v+9 v+8 v+7 v 104 144 v+2 v+1 v+0 v 104
Passagem de Vetor para Função consiste em passar o endereço da primeira posição do vetor função deve ter parâmetro do tipo ponteiro para armazenar valor passar um vetor para uma função é equivalente a passar o endereço inicial do vetor elementos do vetor não são copiados para a função argumento copiado é apenas o endereço do primeiro elemento /* Cálculo da média de uma sequência de reais */ #include <stdio.h> /* Função para cálculo da média */ float media (int n, float * v) int i; float s = 0.0; for (i=0; i<n; i++) s += v[i]; // ou: s += *(v+i); return s/n; parâmetro do tipo ponteiro para float int main (void) float v[] = 2, 3, 0, 6, 4; float med; med = media(5,v); printf ("Media = %f\n", med); return 0;
Passagem de Vetor para Função - continuação função pode alterar os valores dos elementos do vetor pois recebe o endereço do primeiro elemento do vetor (e não os elementos propriamente ditos) /* Incrementa elementos de um vetor */ #include <stdio.h> void incr_vetor ( int n, int * v ) int i; for (i=0; i<n; i++) v[i]++; int main (void) int a[ ] = 1, 3, 5; incr_vetor(3,a); printf("%d %d %d \n", a[0], a[1], a[2]); return 0; saída do programa será 2 4 6
Uso da Memória Uso da memória: memória estática: código do programa variáveis globais variáveis estáticas memória dinâmica: variáveis alocadas dinamicamente memória livre variáveis locais Low Memory High Memory memória estática memória dinâmica Código do programa Variáveis globais e Variáveis estáticas Variáveis alocadas dinamicamente Memória livre Variáveis locais (Pilha de execução)
Alocação Dinâmica Requer a biblioteca padrão stdlib (que também contém outros tipos e funções úteis) void * malloc(int num_bytes); void free(void * p); void * realloc(void * p, int num_bytes); Rigorosamente falando, o tipo int especificado acima deve ser o tipo size_t. Isto é: void * malloc(size_t num_bytes). Dependendo da implementação, size_t é unsigned int ou unsigned long.
Alocação Dinâmica Função malloc : recebe como parâmetro o número de bytes que se deseja alocar retorna um ponteiro genérico para o endereço inicial da área de memória alocada, se houver espaço livre: ponteiro genérico é representado por void * em ANSI C, o ponteiro é convertido automaticamente para o tipo apropriado ponteiro pode ser convertido explicitamente (cast). Isto é recomendável, por questões de compatibilidade com outras implementações e de reuso em C++ standard (que exige cast). retorna um endereço nulo, se não houver espaço livre: representado pelo símbolo NULL. malloc(0) geralmente retorna um valor único de ponteiro (válido para free e realloc, mas não para outro uso), mas também pode voltar NULL dependendo da implementação (ANSI C deixa isto livre). Função sizeof : retorna o número de bytes ocupado por um tipo função free : recebe como parâmetro o ponteiro da memória a ser liberada, i.e. um endereço de memória que foi previamente alocada por malloc. free(null) pode ser usada e não tem efeito. Após free(p) seria prudente fazer p=null para não haver um uso descuidado do p liberado.
Alocação Dinâmica #include <stdlib.h> int * v; v = (int *) malloc(10*sizeof(int)); 1 - Declaração: int *v 2 - Comando: v = (int *) malloc (10*sizeof(int)) Abre-se espaço na pilha para Reserva espaço de memória da área livre o ponteiro (variável local) e atribui endereço à variável Código do Programa Variáveis Globais e Estáticas Livre Código do Programa Variáveis Globais e Estáticas 40 bytes Livre 504 v - v 504 free(v);
Alocação Dinâmica tratamento de erro após chamada a malloc imprime mensagem de erro aborta o programa (com a função exit) #include <stdlib.h> v = (int *)malloc(10*sizeof(int)); if (v==null) printf("memoria insuficiente.\n"); exit(1); /* aborta o programa e retorna 1 para o sist. operacional */ lembre que malloc(0) geralmente retorna um ponteiro único (e não NULL)
Alocação Dinâmica #include <stdlib.h> #include <stdio.h> float * somavetores3d(float * u, float * v) float * p = (float *)malloc(3*sizeof(float)); p[0] = u[0] + v[0]; p[1] = u[1] + v[1]; p[2] = u[2] + v[2]; return p; int main(void) float u[] = 2, 2, 3 ; float v[] = 3, 3, 3 ; float * p; int i; p = somavetores3d(u, v); for (i = 0;i < 3;i++) printf("p[i]= %.1f\n", p[i]); free(p); return 0; variável p alocada dinamicamente área de memória que a variável p ocupa permanece válida mesmo após o término da função somavetores3d função que chama somavetores3d pode acessar o ponteiro retornado um problema - alocação dinâmica para cada chamada da função: ineficiente do ponto de vista computacional requer que a função que chama seja responsável pela liberação do espaço Se fosse float p[3]; no lugar de float * p= (float *) malloc(3*sizeof(float));, daria erro, porque a área de memória alocada por float p[3] deixaria de ser válida quando a função terminasse.
Alocação Prévia #include <stdlib.h> #include <stdio.h> void somavetores3d(float * u, float * v, float * p) p[0] = u[0] + v[0]; int main(void) p[1] = u[1] + v[1]; p[2] = u[2] + v[2]; float u[] = 2, 2, 3 ; float v[] = 3, 3, 3 ; float * p = (float *)malloc(3*sizeof(float)); int i; somavetores3d(u, v, p); for (i = 0;i < 3;i++) printf("p[i]= %.1f\n", p[i]); free(p); return 0; espaço de memória para o resultado passado pela função que chama: função somavetores3d recebe três vetores, dois vetores com dados de entrada um vetor para armazenar o resultado solução mais adequada, pois não envolve alocação dinâmica