Docsity
Docsity

Prepare-se para as provas
Prepare-se para as provas

Estude fácil! Tem muito documento disponível na Docsity


Ganhe pontos para baixar
Ganhe pontos para baixar

Ganhe pontos ajudando outros esrudantes ou compre um plano Premium


Guias e Dicas
Guias e Dicas

Alocação Dinâmica, Notas de aula de Informática

ble ble ble

Tipologia: Notas de aula

2012

Compartilhado em 13/09/2012

silveiro-uiembe-7
silveiro-uiembe-7 🇧🇷

1 documento

1 / 8

Toggle sidebar

Esta página não é visível na pré-visualização

Não perca as partes importantes!

bg1
Alocação Dinâmica
Alocação Dinâmica é o processo de solicitar e utilizar memória durante a execução de
um programa. Ela é utilizada para que um programa em C utilize apenas a memória
necessária pra 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çoes serão necessárias. Neste
caso, através da alocação dinâmica, os espaços necessários para armazenar os valores
seriam alocados dinamicamente, durante a execução do programa, e conforme a
necessidade de armazenamento.
Sendo assim, a alocação dinâmica de memória deve ser utilizada quando não se sabe,
por algum motivo ou aplicação, quanto espaço de memória será necessário pra o
armazenamento de algum ou alguns valores.
Existem funções em C próprias para fazer o "pedido" de memória. Isso porque a
memória pode estar cheia, e não haver mais espaço disponível. Neste caso, um pedido
de alocação será recusado.
Veremos apenas 2 funções básicas:
F 0
B 7 malloc - pedido de alocação de memória
formato: (void*) malloc(tamanho em bytes)
Esta função faz um pedido de memória ao computador, durante a execução do
programa.
Para que este pedido seja feito é preciso informar a quantidade de bytes desejada. Para
que possamos determinar qual o tamanho em bytes que queremos, utilizamos a função
sizeof.
O retorno de malloc é um ponteiro genérico e deve ser configurado para o tipo alocado.
Por exemplo:
pt = (int*) malloc (sizeof(int))
faz um pedido de alocação de memória para o tamanho de um inteiro ( sizeof(int) )
recebe o retorno de malloc como um endereço (ponteiro) de inteiro, armazenando esse
endereço em pt. Sendo que pt é do tipo ponteiro de inteiro, neste caso.
Observe que a memória alocada não possui nome, mas pt terá a localização dessa
memória através do endereço retornado por malloc. Obviamente pt não é uma variável
alocada dinamicamente (pois ela tem nome!), mas saberá a localização de uma que é.
Caso o pedido de memória seja recusado, pt receberá 0. Assim, é importante sempre
testar se um pedido de memória foi aceito checando se pt, ou a variável que recebe o
retorno de malloc, é igual ou não a zero.
F 0
B 7 free - liberação de memória alocada dinamicamente
formato: free(endereço)
Esta função libera memória alocada dinamicamente.
Toda memória alocada dinamicamente deve ser liberada antes do término de um
programa, caso contrário ela não estará disponível para outras aplicações ou programas.
pf3
pf4
pf5
pf8

Pré-visualização parcial do texto

Baixe Alocação Dinâmica e outras Notas de aula em PDF para Informática, somente na Docsity!

Alocação Dinâmica

Alocação Dinâmica é o processo de solicitar e utilizar memória durante a execução de um programa. Ela é utilizada para que um programa em C utilize apenas a memória necessária pra 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çoes serão necessárias. Neste caso, através da alocação dinâmica, os espaços necessários para armazenar os valores seriam alocados dinamicamente, durante a execução do programa, e conforme a necessidade de armazenamento. Sendo assim, a alocação dinâmica de memória deve ser utilizada quando não se sabe, por algum motivo ou aplicação, quanto espaço de memória será necessário pra o armazenamento de algum ou alguns valores. Existem funções em C próprias para fazer o "pedido" de memória. Isso porque a memória pode estar cheia, e não haver mais espaço disponível. Neste caso, um pedido de alocação será recusado. Veremos apenas 2 funções básicas:

F 0 B 7 malloc - pedido de alocação de memória _formato: (void) malloc(tamanho em bytes)_*

Esta função faz um pedido de memória ao computador, durante a execução do programa. Para que este pedido seja feito é preciso informar a quantidade de bytes desejada. Para que possamos determinar qual o tamanho em bytes que queremos, utilizamos a função sizeof. O retorno de malloc é um ponteiro genérico e deve ser configurado para o tipo alocado. Por exemplo: pt = (int*) malloc (sizeof(int)) faz um pedido de alocação de memória para o tamanho de um inteiro ( sizeof(int) ) recebe o retorno de malloc como um endereço (ponteiro) de inteiro, armazenando esse endereço em pt. Sendo que pt é do tipo ponteiro de inteiro, neste caso.

Observe que a memória alocada não possui nome, mas pt terá a localização dessa memória através do endereço retornado por malloc. Obviamente pt não é uma variável alocada dinamicamente (pois ela tem nome!), mas saberá a localização de uma que é. Caso o pedido de memória seja recusado, pt receberá 0. Assim, é importante sempre testar se um pedido de memória foi aceito checando se pt , ou a variável que recebe o retorno de malloc, é igual ou não a zero.

F 0 B 7 free - liberação de memória alocada dinamicamente formato: free(endereço)

Esta função libera memória alocada dinamicamente. Toda memória alocada dinamicamente deve ser liberada antes do término de um programa, caso contrário ela não estará disponível para outras aplicações ou programas.

"Você é responsável por liberar a memória que você alocou!"

Uma vez que a única maneira de chegar a uma memória alocada dinamicamente é através de outra variável, esta variável (que contém o endereço da memória alocada) é utilizada pelo free por conter o endereço que deseja-se liberar.

Por exemplo:

free(pt);

para liberar a memória alocada no exemplo anterior

Aplicações da alocação dinâmica:

  • listas ligadas
  • pilhas
  • filas
  • árvores
  • grafos

Observações importantes:

  • sempre que for feito um pedido de memória dinamicamente, deve-se verificar se o pedido foi aceito através da variável que recebeu o endereço que o malloc retornou.
  • a memória alocada dinamicamente NÃO tem nome, e deve sempre ser referenciada através de uma outra variável. Ou seja, se você tem duvida se uma variável foi alocada dinamicamente ou não, faça a simulação do programa (manual) e verifique se o local onde você está guardando uma informação possui ou não nome.
  • free só libera memória alocada dinamicamente (memória sem nome)
  • (^) a função sizeof retorna o número de bytes que um dado ocupa. Essa função não é utilizada somente com o malloc, mas neste caso ajuda-nos a "descobrir" quantos bytes um tipo ocupa. Se você quiser ver quantos bytes uma variável qualquer ocupa use: a = sizeof( variavel ) , onde a será onde vai ser armazenado o retorno de sizeof, ou seja, o número de bytes ocupado pela variável.

Alocação de memória , em ciência da computação, consiste no processo de solicitar/ utilizar memória durante o processo de execução de um programa de computador. A alocação de memória no computador pode ser dividida em dois grupos principais:

  • Alocação Estática: os dados tem um tamanho fixo e estão organizados seqüencialmente na memória do computador. Um exemplo típico de alocação estática são as variáveis globais e arrays;
  • Alocação Dinâmica: os dados não precisam ter um tamanho fixo, pois podemos definir para cada dado quanto de memória que desejamos usar. Sendo assim vamos alocar espaços de memória (blocos) que não precisam estar necessariamente organizados de maneira seqüencial, podendo estar distribuídos de forma dispersa (não ordenada) na memória do computador. Na alocação dinâmica, vamos pedir para alocar/desalocar blocos de memória, de acordo com a nossa necessidade, reservando ou liberando blocos de memória durante a execução de um programa. Para poder “achar” os blocos que estão dispersos ou
  • /* código para introduzir um array de n números e ordená- los */
  • ...
  • free( a );
  • }

cada variável ficava guardada numa posição de memória. Por exemplo, se fizéssemos um programa que contivesse a seguinte declaração, int x = 9;

o x poderia ir parar à posição de memória E2 quando o programa fosse executado. Na realidade, as coisas não são bem assim. Cada posição de memória corresponde apenas a um byte e uma variável inteira ocupa geralmente 4 bytes. Ou seja, o número 9 não vai estar representado numa única posição de memória mas sim em 4 posições de memória (ex: E2, E3, E4 e E5). Aliás, aquilo que está nessas 4 posições de memória é a representação em binário do número 9. A figura que se segue dá esta visão mais detalhada da memória.

Alocação dinâmica

A alocação dinâmica é o processo que aloca memória em tempo de execução. Ela é utilizada quando não se sabe ao certo quanto de memória será necessário para o armazenamento das informações, podendo ser determinadas em tempo de execução conforme a necessidade do programa. Dessa forma evita-se o desperdício de memória.

No padrão C ANSI existem 4 funções para alocações dinâmica pertencentes a biblioteca stdlib.h. São elas malloc(), calloc(), realloc() e free(). Sendo que as mais utilizadas são as funções malloc() e free(). Além das funções mencionadas acima existem outras que não serão abordadas neste tutorial, pois não são funções padrões.

A alocação dinâmica é muito utilizada em problemas de estrutura de dados, por exemplo, listas encadeadas, pilhas, filas, arvores binárias e grafos. As funções malloc() e calloc() são responsáveis por alocar memória, a realloc() por realocar a memória e por ultimo a free() fica responsável por liberar a memória alocada.

A sintaxe da função malloc() é dada por:

Esta função recebe como parâmetro “size” que é o número de bytes de memória que se deseja alocar. O tipo size_t é definido em stdlib.h como sendo um inteiro sem sinal. O interessante é que esta função retorna um ponteiro do tipo void podendo assim ser atribuído a qualquer tipo de ponteiro.

No exemplo abaixo, suponha que seja necessário no meio do código alocar uma memória com 150 bytes, para isto seria necessário digitar as seguintes linhas de código:

No programa abaixo podemos verificar alguns problemas que podem ser facilmente resolvidos se tivéssemos utilizado alocação dinâmica.

O exemplo acima é muito simples, mas demonstra em que situação deve utilizar alocação dinâmica. Analisando o programa mostrado vemos que não se sabe a quantidade de valores que a pessoa vai inserir no vetor por esse motivo declaramos um vetor muito grande. O problema está se a pessoa, por exemplo, deseja colocar apenas 3 elementos no vetor. Como o vetor foi declarado com o tamanho igual a 100, o que acontece é o desperdício de memória e caso passe de 100 haverá um estouro. Portanto a melhor solução seria utilizar alocação dinâmica, ou seja, toda vez que não se sabe ao certo a quantidade de elementos a serem utilizados deve-se utilizar a alocação dinâmica.

O mesmo exemplo mostrado anteriormente com o uso de alocação dinâmica (usando a função malloc() ) é mostrado logo abaixo:

Agora o usuário pode digitar o tamanho do vetor que quiser que não terá desperdício de memória e o vetor a ser alocado será do tamanho digitado pelo usuário.

A função malloc() utilizada no programa acima, cuja a sintaxe foi mostrada, devolve um ponteiro do tipo void, desta forma pode-se ser atribuído a qualquer tipo de ponteiro (no nosso exemplo é atribuído a um ponteiro do tipo inteiro). A memória alocada pela função malloc(), como também por outras funções que vamos ver no decorrer deste tutorial, devem ser obtida do heap. Heap é a região de memória livre do seu computador. Desta forma é necessário verificar se a memória livre do seu computador é suficiente para o armazenamento e isto pode ser feito da seguinte forma:

Caso a função malloc() devolver o valor nulo significa que não há memória suficiente e nesse caso o programa deve imprimir na tela a mensagem “Memória insuficiente” e imediatamente terminar o programa que é feito através da função exit().

função foi necessário inserir no cabeçalho “#include <string.h>”. Existem outras funções para se trabalhar com string que serão explicados no próximo tutorial.

Nos exemplos aqui mostrado o system(“Pause”) tem o mesmo papel que o getch() e serve para que o programa de uma pausa. O comando "system" roda qualquer comando DOS. E por ultimo para se utilizar o system(“Pause”) é necessário inserir no cabeçalho “#include<stdlib.h>”.

Conclusão

Neste tutorial vimos em que situações devem utilizar a alocação dinâmica e como elas são importantes para diversas aplicações.

Alocação dinâmica de memória

O compilador reserva espaço na memória para todos os dados declarados explicitamente, mas se usarmos ponteiros precisamos reservar o espaço necessário e colocar o endereço inicial nos mesmos. Para isto, podemos usar o endereço de uma variável definida previamente ou reservar o espaço necessário no momento que precisemos. Este espaço que precisamos reservar em tempo de execução é chamada de memória alocada dinamicamente.

Refere-se à possibilidade de termos o nosso programa a correr e o utilizador ter de inserir dados e como tal não sabemos exactamente a quantidade de dados que o utilizador vai colocar, portanto temos de arranjar uma memória que nos permita lidar com esta indeterminação quanto à quantidade de dados inseridos.

Este é o caso em que não sabemos no momento da programação a quantidade de dados que deverão ser inseridos mas o programa já está a correr. É tentar responder a perguntas: quantas pessoas existem na tua turma? Quantas letras vamos escrever, etc. Em vez de estarmos a prever um limite superior para abarcar todas as situações, temos esta possibilidade do dinâmico. Além de que colocar no momento da programação cria reserva de memória por isso, estaríamos a reservar memória para um limite que possivelmente não iríamos ter necessidade. O exemplo típico disto é os processadores de texto. em que não sabemos a quantidade de letras que o utilizador vai escrever.

Vamos voltar a uma ponta solta num dos capítulos anteriores, onde queríamos fazer com que o utilizador dissesse quantos elementos do array é que se deveria utilizar. Já dissemos antes que o declarador do nº de elementos do array tem de ser ou uma constante ou um literal, mas não pode ser uma variável. Isso dá erro. Aqui vai o exemplo desse erro:

#include

using namespace std;

int main ()

{

int numTests;

cout << "Enter the number of test scores:";

cin >> numTests;

int testScore[numTests];

system ("pause");

return 0;

}

Alocar dinamicamente Arrays

Ora o que fizemos antes com variáveis, vamos ter de fazer com arrays.

int *pt = new int[1024]; //allocates an array of 1024 ints

double *myBills = new double[10000];

/* This doesn't mean I owe 10000.0, but rather allocates an array of 10000 doubles to hold the amounts of the thousands of bills I receive monthly. */

Notar a diferença:

int *pt = new int[1024]; //allocates an array of 1024 ints

int *pt = new int(1024); //allocates a single int with value 1024

a melhor maneira para alocar um array dinamicamente é usar o loop

int *buff = new int[1024];

for (i = 0; i < 1024; i++)

{

*buff = 52; //Assigns 52 to each element;

buff++;

}

ou se quisermos desta maneira

int *buff = new int[1024];

for (i = 0; i < 1024; i++)

{

buff[i] = 52; //Assigns 52 to each element;

}

para utilizar o delete em arrays

delete[] pt;

delete[] myBills;