Baixe o app para aproveitar ainda mais
Prévia do material em texto
Ciência da Computação Tecnologia em Análise e Desenvolvimento de Sistemas Estrutura de Dados I INF1014 - CCB1044 Alocação Dinâmica de Memória SUMÁRIO • Conceito de Alocação Dinâmica • Alocação Dinâmica x Alocação Estática • Funções para Alocação de Memória • Vetores Alocados Dinamicamente • Matrizes Alocadas Dinamicamente • Estruturas Alocadas Dinamicamente Alocação Dinâmica de Memória • Conceito de Alocação Dinâmica – é o processo pelo qual um programa pode solicitar e utilizar um bloco de memória de tamanho arbitrário, durante sua execução. – é utilizada para que um programa em C utilize apenas a memória necessária para sua execução, sem desperdícios de memória. • um exemplo de desperdício de memória é quando um vetor de 1000 posições é declarado quando não se sabe, de fato, se as 1000 posições serão necessárias – a alocação dinâmica de memória deve ser utilizada quando não se sabe quanto espaço de memória será necessário para o armazenamento de algum ou alguns valores. – existem funções em C próprias para fazer o "pedido" de memória. – um pedido de alocação será recusado se a memória estiver cheia. Alocação Dinâmica de Memória • Alocação Dinâmica x Alocação Estática – alocação estática • usa variáveis locais e globais, simples ou em forma de arranjo • exige que o programador saiba, de antemão, o espaço necessário • variáveis globais ou locais estáticas ocupam um espaço fixo durante toda a execução do programa • variáveis locais ocupam espaço na pilha, cujo tamanho varia conforme a necessidade (funções recursivas demandam mais memória de pilha) – alocação dinâmica • o espaço é ocupado no heap, que também varia conforme a necessidade memória do sistema variáveis globais programa memória livre (heap) pilha em casos extremos a pilha pode colidir com o heap e ocorrerá uma falha Alocação Dinâmica de Memória • Alocação Dinâmica x Alocação Estática – alocação estática • uso de variáveis globais (ou estáticas): – espaço reservado existe enquanto o programa estiver sendo executado • uso de variáveis locais: – espaço existe apenas enquanto a função que declarou a variável está sendo executada – liberado para outros usos quando a execução da função termina – alocação dinâmica • espaço de memória é requisitado em tempo de execução e permanece reservado até que seja explicitamente liberado • depois de liberado, espaço estará disponibilizado para outros usos e não pode mais ser acessado • espaço alocado e não liberado explicitamente, será automaticamente liberado ao final da execução Alocação Dinâmica de Memória • Funções para Alocação de Memória – Função malloc (stdio.h) • função para solicitar a alocação de um dado número de bytes • 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* – ponteiro é convertido automaticamente para o tipo apropriado – ponteiro pode ser convertido explicitamente • retorna um endereço nulo, se não houver espaço livre: – representado pelo símbolo NULL número_de_bytes: número de bytes que se quer alocar (o tipo size_t é um inteiro sem sinal definido em stdio.h) void* malloc(size_t número_de_bytes) como o heap não é infinito, após a alocação é necessário testar o valor devolvido por malloc() (ex_14) (ex_15) Alocação Dinâmica de Memória • Funções para Alocação de Memória – Função malloc (stdio.h) • Exemplos (serão vistos em detalhe mais adiante) – vetor de 10 inteiros – matriz bidimensional de inteiros // equivalente a int aVetor[10] int *aVetor; aVetor = (int *) malloc(10 * sizeof(int)); if (aVetor == NULL) printf (“Memória insuficiente”); // equivalente a int aMatriz[2][3] int **amatriz; aMatriz = (int**) malloc(2 * sizeof(int*)); //linhas for( i=0; i<2 ; i++ ) { aMatriz[i] = (int*) malloc(3 * sizeof(int)); //colunas } Alocação Dinâmica de Memória • Funções para Alocação de Memória – Função free (stdio.h) • função que libera bloco de memória alocado previamente • quando não se deseja mais uma área alocada, deve-se liberá-la através da função free. void free(void *nome) nome: nome do ponteiro para a memória alocada por malloc() é importante nunca usar free() com um argumento inválido, pois, isso destruiria a lista de memória livre (ex_16) Alocação Dinâmica de Memória • Funções para Alocação de Memória – Função calloc (stdio.h) • função para solicitar a alocação de uma dada quantidade de objetos de um determinado tamanho void* calloc (size_t quantidade, size_t tamanho) a única diferença entre malloc e calloc é que a última função, além de alocar o espaço, também inicializa o mesmo com zeros (ex_17) quantidade : quantidade de objetos que se quer alocar tamanho : número de bytes do objeto que se quer alocar Alocação Dinâmica de Memória • Funções para Alocação de Memória – Função realloc (stdio.h) • função que permite que uma área previamente alocada seja aumentada ou diminuída • o conteúdo do objeto será mantido até um tamanho igual ao menor dos dois tamanhos, novo e antigo • se o novo tamanho requerer movimento, o espaço reservado anteriormente será liberado • se o novo tamanho for maior, o conteúdo da porção de memória reservada a mais ficará com um valor sem especificação • se o tamanho número_de_bytes for igual a 0 e nome não for um ponteiro nulo, o objeto previamente reservado será liberado. void* realloc(void *nome, size_t número_de_bytes) (ex_18) nome: nome do ponteiro para a área de memória alocada que se quer reajustar número_de_bytes: novo número de bytes que se quer que a dada área ocupe Alocação Dinâmica de Memória • Vetores Alocados Dinamicamente – vetores de tamanho dinâmico, determinado em tempo de execução #include <stdio.h> #include <stdlib.h> int main(void) { int *p; int i,k, n; printf("\nDigite a quantidade de números que serão digitados ->"); scanf("%d", &i); p = (int *)(malloc(i*sizeof(int))); if (p == NULL ){ printf("\nErro de alocacao de memoria"); exit(1); } for(k=0; k<i; k++){ printf("Digite o numero para o indice %d ->", k); scanf("%d", &p[k]); } for(k=0;k<i;k++){ printf("O numero do indice %d eh %d\n", k, p[k]); } //continua A função malloc reserva espaço suficiente para um vetor de inteiros. Por ex., para 5 elementos, serão reservados 20 bytes, considerando que cada inteiro ocupa 4 bytes na memória. Alocação Dinâmica de Memória • Vetores Alocados Dinamicamente – vetores de tamanho dinâmico, determinado em tempo de execução printf("\nDigite quantos elementos quer adicionar ao vetor ->"); scanf("%d", &n) p = (int *)(realloc(p,(i+n)*sizeof(int))); if( p == NULL ){ printf("\nErro de re-alocacao de memoria"); exit(1); } for(;k<(n+i);k++){ printf("Digite o numero para o indice %d ->", k); scanf("%d", &p[k]); } for( k=0;k<(i+n);k++) { printf("O numero do indice %d eh %d\n", k, p[k]); } free(p); return 0; } A função realloc aumenta ou diminui o tamanho do vetor dinamicamente. Ela recebe o ponteiro para o vetor anterior e retorna o novo espaço alocado. Alocação Dinâmica de Memória • Vetores Alocados Dinamicamente – o uso de vetores locais a funções requer cuidado – exemplo • produto vetorial de dois vetoresu e v em 3D, representados pelas três componentes x, y, e z – variável p declarada localmente: » área de memória que a variável p ocupa deixa de ser válida quando a função prod_vetorial termina » função que chama prod_vetorial não pode acessar a área apontada pelo valor retornado float* prod_vetorial (float* u, float* v) { float p[3]; 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; } Alocação Dinâmica de Memória • Vetores Alocados Dinamicamente – exemplo (continuação) • produto vetorial de dois vetores u e v em 3D – 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 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; } Alocação Dinâmica de Memória • Vetores Alocados Dinamicamente – exemplo (continuação) • produto vetorial de dois vetores u e v em 3D – 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 void prod_vetorial (float* u, float* v, float* p) { 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]; } Alocação Dinâmica de Memória • Matrizes Alocadas Dinamicamente – A alocação dinâmica para matrizes pode ser realizada de duas formas: • utilizando um vetor de ponteiros , mantendo alocação estática em uma dimensão; • ou utilizando ponteiro para ponteiro. linha[0] linha[1] linha[LINHAS] linha int *linha[LINHAS]; linha[i] = malloc(2*(i+1)* sizeof(int)); linha[0][1] linha[0][0] linha[1][0] linha[1][3] *(matriz+0) *(matriz+1) *(matriz+n) matriz int **matriz; matriz = (int**)malloc(lin*sizeof(int*)); *(*(matriz+0)+1) *(*(matriz+0)+0) *(*(matriz+1)+1) *(*(matriz+1)+0) *(matriz+i) = (int*)malloc(col*sizeof(int)); Linhas de tamanhos diferentes. Alocação Dinâmica de Memória • Matrizes Alocadas Dinamicamente – Exemplo 1 - utiliza um vetor de ponteiros (correspondendo ao primeiro índice da matriz), sendo que cada ponteiro aponta para o início de uma linha da matriz. #include <stdio.h> #include <stdlib.h> #include <string.h> #define LINHAS 10 #define MAXCOLUNAS 60 int main (void) { char *linha[LINHAS]; char temp[MAXCOLUNAS]; int i; for (i = 0; i < LINHAS ; i++) { printf ("Entre com a linha %d.\n", i); gets (temp); if (!(linha[i] = (char *)malloc((strlen(temp)+1) * sizeof(char )))) { printf("Sem memoria para vetor %d.\n", i); return 1; } strcpy (linha[i], temp); } for (i = 0; i < LINHAS ; i++) { printf ("Linha %d %s.\n", i, linha[i]); } return 0; } Alocação Dinâmica de Memória • Matrizes Alocadas Dinamicamente – Exemplo 2 - utiliza ponteiro para ponteiro. #include <stdio.h> #include <stdlib.h> int main (void) { int ** matriz; //ponteiro para os ponteiros int lin , col; //num. de linhas e colunas int lin1, lin2; //linhas que serão trocadas char linha [80]; //linha de dados int i, j; int *temp; puts("Qual o numero de linhas?"); gets(linha); lin = atoi(linha); matriz = (int **)malloc (lin*sizeof(int*)); if (!matriz ) { puts ("Nao ha memoria para alocar"); return 1; } puts ("Qual o numero de colunas?"); gets (linha); col = atoi(linha); for (i=0; i<lin; i++) { *(matriz +i) = (int*)malloc(col*sizeof(int)); if (!*(matriz +i)) { printf("Sem espaco p/ a linha %d", i); return 1; } } puts ("Entre com os dados"); for (i=0; i<lin; i++) { printf (“Entre com a linha %d\n", i); for (j=0; j< col; j++) { printf("Elemento %d %d\n", i, j); scanf("%d", *(matriz +i) +j); } } gets(linha); //só para limpar buffer puts("Qual a 1a linha a ser trocada ?"); gets(linha); lin1 = atoi(linha); puts("Qual a 2a linha a ser trocada ?"); gets(linha); lin2 = atoi(linha); temp = *(matriz + lin1); *(matriz + lin1) = *( matriz + lin2 ); *(matriz + lin2 ) = temp ; puts ("Dados trocados ."); for (i=0; i<lin; i++) { for (j=0; j< col; j++) { printf("%7d ", *(*(matriz +i) +j)); } return 0; } Alocação Dinâmica de Memória • Estruturas Alocadas Dinamicamente – estruturas também podem ser alocadas dinamicamente. #include <stdio.h> #include <stdlib.h> struct ST_DADOS { char nome[40]; float salario; // estrutura dentro de uma estrutura struct nascimento { int ano; int mes; int dia; } dt_nascimento; }; int main(void) { //ponteiro para a estrutura struct ST_DADOS *p; p = (struct ST_DADOS *)malloc(sizeof(struct ST_DADOS)); // p->nome é um ponteiro, não precisa do & printf("\nEntre com o nome ->"); scanf("%s", p->nome); printf("Entre com o salario ->"); scanf("%f", &p->salario); printf("Entre com o nascimento ->"); scanf("%d%d%d", &p->dt_nascimento.dia, &p->dt_nascimento.mes, &p->dt_nascimento.ano); printf("\n===== Dados digitados ===="); printf("\nNome = %s", p->nome); printf("\nSalario = %f", p->salario); printf("\nNascimento = %d/%d/%d\n", p->dt_nascimento.dia, p->dt_nascimento.mes, p->dt_nascimento.ano); free(p); return 0; }
Compartilhar