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: Exemplo: v+0 : primeiro elemento de v... v+9 : último elemento de v &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 e da variância de 10 reais (segunda versão) */ #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]; return s/n; parâmetro do tipo ponteiro para float
/* Função para cálculo da variância */ float variancia (int n, float * v, float m) int main (void) int i; float s = 0.0; for (i=0; i<n; i++) s += (v[i] - m) * (v[i] - m); return s/n; float v[10]; float med, var; int i; for (i=0; i<10; i++ ) scanf("%f", &v[i]); med = media(10,v); var = variancia(10,v,med); printf ("Media = %f Variancia = %f \n", med, var); return 0;
Passagem de Vetor para Funçã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
memória dinâmica memória estática 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 Código do programa Variáveis globais e Variáveis estáticas Variáveis alocadas dinamicamente Memória livre Variáveis locais ( execução (Pilha de
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). Operador 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-seespaço na pilha para Reserva espaçodememória da área livre oponteiro(variável local) eatribui endereçoàvariável Códigodo Programa Variáveis GlobaiseEstáticas Livre Códigodo Programa Variáveis GlobaiseEstá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 float * prod_vetorial (float * u, float * v) float * p = (float *)malloc(3*sizeof(float)); p[0] = u[1]*v[2] v[1]*u[2]; p[1] = u[2]*v[0] v[2]*u[0]; p[2] = u[0]*v[1] v[0]*u[1]; return p; 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 prod_vetorial função que chama prod_vetorial pode acessar o ponteiro retornado 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 ( p void prod_vetorial (float* u, float* v, float* p[0] = u[1]*v[2] v[1]*u[2]; p[1] = u[2]*v[0] v[2]*u[0]; p[2] = u[0]*v[1] v[0]*u[1]; espaço de memória para o resultado passado pela função que chama: função prod_vetorial 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