UDESC - SBS Departamento de Sistemas de Informação LPG - I: Alocação Dinâmica de Memória - Ponteiros Prof. Flavio Marcello Strelow [email protected] Memória Disponível no Computador PROGRAMA ÁREA LIVRE Memória livre, gerenciada pelo sistema operacional Código executável: - instruções (compilador) - armazenamento do dados (estrutura dos dados) Alocação de Memória - Estática Estática Quantidade total de memória utilizada pelos dados é previamente conhecida e definida de modo imutável, no próprio código-fonte do programa. Durante toda a execução, a quantidade de memória utilizada pelo programa não varia. Lista de variáveis declaradas. Alocação de Memória - Estática Implementação simples: vetores (array) Vantagem: acesso indexado (vi)- todos os elementos da estrutura são igualmente acessíveis Desvantagens: tamanho fixo (#define TAM 1000) tempo de compilação alocados em memória de forma estática Alocação de Memória - Estática Ao se determinar o máximo de elementos que o vetor irá conter, pode-se ocorrer um dos seguintes casos: Subdimensionamento: haverá mais elementos a serem armazenados do que o vetor é capaz de conter; Superdimensionamento: na maior parte do tempo, somente uma pequena porção do vetor será realmente utilizada. Alocação de Memória - Dinâmica Dinâmica Quanto o programa é capaz de criar novas variáveis enquanto está sendo executado. Alocação de memória para componentes individuais no instante em que eles começam a existir durante a execução do programa. Alocação Estática x Alocação Dinâmica Alocação Dinâmica Implementação eficiente: ponteiros ou apontadores Vantagens: tamanho variável tempo de execução alocados em memória de forma dinâmica Desvantagem, ou restrição: capacidade da memória, acesso seqüencial Alocação de Memória - Ponteiros No padrão C ANSI que define as funções para a alocação dinâmica (alocar e liberar blocos de memória em tempo de execução) estão disponíveis na biblioteca stdlib.h. malloc: alocar memória. free: liberar áreas da memória ocupadas. Precisaremos tambem do: sizeof: retorna o tamanho de uma variável. Operador sizeof() sizeof sizeof(<expressão> | <tipo>) Retorna o número de bytes necessários para armazenar um objeto na memória, ou seja, saber o tamanho de tipos . O objeto pode ser um vetor, estrutura(struct) ou uma expressão como 5+9 ou 2.5*3. Alocação de Memória - malloc malloc void* malloc(tamanho_a_alocar); Recebe o número de bytes a alocar. Retorna um apontador void para a base da região contígua alocada na memória ou NULL se não for possível alocá-la. É responsabilidade do programador liberar a memória alocada dinamicamente com free. Produz erros estranhos quando usada para liberar um espaço que já foi liberado. Alocação de Memória - Exemplos Alocação de memória para um inteiro: int *p = malloc( 3 * sizeof(int)); Alocação de memória para um array de n reais: float *p = malloc(n * sizeof(float)); Representação Interna da Variável do Tipo Ponteiro: aloca a variável estaticamente void main() { int *p; I aloca a variável dinamicamente p = (int *) malloc(sizeof(int)); II *p = 10; III ... IV free(p); } memória usada pelo programa endereço 1FFA Lixo 10 1FFA p: Lixo memória livre no sistema Entendendo o código: I - int *p; A variável p é um ponteiro para um número inteiro, ou seja, “aponta” para um endereço de memória que será “alocado” para armazenar um número inteiro (2 bytes) II - p = (int *) malloc(sizeof(int)); Solicita ao sistema operacional 2 bytes da memória livre e o “endereço do espaço alocado” é colocado na variável ponteiro p III - *p = 10; No endereço apontado por p armazena o número inteiro 10 IV - free(p); Libera o espaço de memória ocupado cujo endereço está em p (devolve o recurso ao sistema operacional) Exemplo Faça um programa para ler 10 números reais e armazene em um vetor alocado dinamicamente. Depois, imprima os elementos lidos. Exemplo #include <stdio.h> #include <conio.h> #include <stdlib.h> #define TAM 10 int main() { int *pti, i; pti= (int *) malloc(sizeof(int) * TAM); if (pti == NULL) { /* verifica alocação, (poderia ser if(!pti)) */ printf("Erro ao alocar memória!\n"); return 1; /* sai do programa */ } for (i=0; i<TAM; i++) { printf("Digite um numero inteiro: "); scanf("%d", &pti[i]); /* lê e armazena no vetor de endereços */ } /* Impressao do ponteiro */ for (i=0; i<TAM; i++) printf("%d", pti[i]); free(pti); // libera memoria. return 0; } Alocação de Ponteiros LPG-I Flavio Marcello Exercícios Faça um programa que aloque uma string de 30 caracteres, armazene uma palavra digitada pelo usuário nesta string, imprima na tela e, depois de imprimido, desaloque esta string. Faça um programa que leia 5 strings e armazene em uma matriz de strings. Cada string deve ter seu espaço alocado dinamicamente (considere strings de no máximo 20 caracteres na leitura). 3) Faça um programa que aloque uma string de 30 caracteres, armazene uma palavra digitada pelo usuário nesta string, imprima na tela e, depois de imprimido, desaloque esta string. #include <stdio.h> #include <stdlib.h> main() { char *string; /* alocar a string de 30 caracteres */ string= (char *) malloc(sizeof(char) * 30); if (!string) /* se alocação falhou (se string for igual a NULL) */ { printf("Erro ao alocar memória!\n"); return 1; /* sai do programa */ } printf("Digite uma palavra: "); fgets(string, 30, stdin); printf("A palavra digitada é %s\n", string); free(string); /* desaloca a string */ return 0; } /*4) Faça um programa que leia 5 strings e armazene em uma matriz de strings. Cada string deve ter seu espaço alocado dinamicamente (considere strings de no máximo 20 caracteres). */ #include <stdio.h> #include <stdlib.h> main() { char *mat[5]; int i; for (i=0; i<5; i++) { /* aloca espaço para as strings */ mat[i]= (char *) malloc(sizeof(char) * 20); if (!mat[i]) { printf("Falha na alocação de memória!\n"); return 1; } printf("Digite uma palavra: "); fgets(mat[i], 20, stdin); } /* imprime as strings */ for (i=0; i<5; i++) { puts(mat[i]); free(mat[i]); /* desaloca a string */ } return 0; /* OBS: Quando um dado é alocado dinamicamente, é importante desalocá-lo antes de encerrar o programa. Se isso não for feito, a variável continuará ocupando espaço desnecessariamente após o término da execução do programa. Também é importante testar se ocorreu algum erro na alocação, para tratá-lo, se houver. */ }