Você está na página 1de 27

Aula 04 - Alocação dinâmica de

memória
PROF. MS ALESSANDRO DIAS

Material elaborado pelo PROF. MS. CASSIANO R. N. MORALLES


Alocação dinâmica de memória

● Declarações alocam espaço na memória para as variáveis;


● A quantidade de memória a alocar só se torna conhecida durante
a execução do programa;
● A alocação dinâmica é administrada pelas funções malloc, realloc
e free (biblioteca stdlib);
○ #include <stdlib.h>
Alocação dinâmica de memória
● A função malloc
○ malloc (o nome é uma abreviatura de memory allocation)
aloca espaço para um bloco de bytes consecutivos na
memória RAM (= random access memory) do computador e
devolve o endereço desse bloco;
○ O número de bytes é especificado no argumento da função:
char *ptr;
ptr = malloc (1);
scanf ("%c", ptr);
Alocação dinâmica de memória

● A função malloc

○ A transformação do ponteiro genérico em


ponteiro-para-char é automática; não é necessário
escrever ptr = (char *) malloc (1);.
○ O endereço é armazenado no ponteiro ptr, que é do
tipo ponteiro-para-char
Alocação dinâmica de memória
● A fim de alocar espaço para um objeto que precisa de mais que 1
byte, convém usar o operador sizeof, que diz quantos bytes o
objeto em questão tem:
typedef struct {
int dia, mes, ano;
} data;
data *d;
d = malloc (sizeof (data));
d->dia = 31; d->mes = 12; d->ano = 2019;
Alocação dinâmica de memória

● O sizeof não é uma função mas um operador, tal como return, por exemplo;
● Os parênteses na expressão sizeof (data) são necessários porque data é
um tipo-de-dados (os parênteses são análogos aos do casting);
● O operador sizeof também pode ser aplicado diretamente a uma variável:
se var é uma variável então sizeof var é o número de bytes ocupado por
var.
● Poderíamos ter escrito d = malloc (sizeof *d) no exemplo acima.
Alocação dinâmica de memória

1-Escreva uma função que receba um byte c (que


pode representar um caractere ASCII, por exemplo)
e transforme-o em uma string, ou seja, devolva uma
string de comprimento 1 tendo c como único
elemento.
Alocação dinâmica de memória

2-Discuta, passo a passo, o efeito do seguinte


fragmento de código:
int *v;
v = malloc (10 * sizeof (int));
Alocação dinâmica de memória

3-Discuta o efeito do seguinte fragmento de


código:
x = malloc (10 * sizeof *x);
Alocação dinâmica de memória
● A função free
○ variáveis alocadas estaticamente dentro de uma
função, também conhecidas como
variáveis automáticas ou locais, desaparecem assim
que a execução da função termina.
Alocação dinâmica de memória
● A função free
○ variáveis alocadas dinamicamente continuam a existir
mesmo depois que a execução da função termina. Se
for necessário liberar a memória ocupada por essas
variáveis, é preciso recorrer à função free.
○ free desaloca a porção de memória alocada por malloc.
Alocação dinâmica de memória

● A instrução free ( ptr) avisa ao sistema que o bloco de


bytes apontado por ptr está disponível para reciclagem.
A próxima invocação de malloc poderá tomar posse
desses bytes.

● Não aplique a função free a uma parte de um bloco de


bytes alocado por malloc (ou realloc). Aplique free
apenas ao bloco todo.
Alocação dinâmica de memória

● O que há de errado com o seguinte fragmento de código?


int *v;
v = malloc (100 * sizeof (int));
v[0] = 999;
free (v+1);
Alocação dinâmica de memória

● A seguinte função promete devolver um vetor


com os 3 primeiros números primos maiores
que 1000. Onde está o erro?
Alocação dinâmica de memória
● Um vetor (= array) com n elementos inteiros pode ser alocado (e depois
desalocado) durante a execução de um programa:
int *v;
int n;
scanf ("%d", &n);
v = malloc ( n * sizeof (int));
for (int i = 0; i < n; ++i)
scanf ("%d", &v[i]);
...
free (v);
Alocação dinâmica de memória

v = malloc (100 * sizeof (int));


int v[100];

Qual a diferença?
Alocação dinâmica de memória
● Matrizes bidimensionais são implementadas como vetores de vetores. Uma
matriz com m linhas e n colunas é um vetor de m elementos cada um dos
quais é um vetor de n elementos. O seguinte fragmento de código faz a
alocação dinâmica de uma tal matriz:
int **M;
M = malloc ( m * sizeof (int *));
for (int i = 0; i < m; ++i)
M[i] = malloc ( n * sizeof (int));

● Portanto, M[i][ j] é o elemento de M que está no cruzamento da linha i com a


coluna j.
Alocação dinâmica de memória

4- Escreva uma função que desaloque a matriz


M alocada acima. Quais devem ser os
parâmetros da função?
Alocação dinâmica de memória

Redimensionamento e a função realloc


● Às vezes é necessário alterar, durante a execução do programa, o tamanho
de um bloco de bytes que foi alocado por malloc. Isso acontece, por
exemplo, durante a leitura de um arquivo que se revela maior que o
esperado.
● Nesse caso, podemos recorrer à função realloc para redimensionar o bloco
de bytes.
Alocação dinâmica de memória
● A função realloc recebe o endereço de um bloco previamente alocado por
malloc (ou por realloc) e o número de bytes que o bloco redimensionado
deve ter. A função aloca o novo bloco, copia para ele o conteúdo do bloco
original, e devolve o endereço do novo bloco.

● Se o novo bloco for uma extensão do bloco original, seu endereço é o


mesmo do original (e o conteúdo do original não precisa ser copiado para o
novo). Caso contrário, realloc copia o conteúdo do bloco original para o novo
e libera o bloco original (invocando free). A propósito, o tamanho do novo
bloco pode ser menor que o do bloco original.
Alocação dinâmica de memória

● Suponha, por exemplo, que alocamos um vetor de 1000 inteiros e depois decidimos que
precisamos de duas vezes mais espaço. Veja um caso concreto:
int *v;
v = malloc (1000 * sizeof (int));
for (int i = 0; i < 990; i++)
scanf ("%d", &v[i]);
v = realloc (v, 2000 * sizeof (int));
for (int i = 990; i < 2000; i++)
scanf ("%d", &v[i]);
Alocação dinâmica de memória
● Nesse exemplo, poderíamos usar a seguinte implementação ad hoc de
realloc:

int *realloc (int *v, unsigned int N) {


int *novo = malloc (N);
for (int i = 0; i < 1000; i++)
novo[i] = v[i];
free (v);
return novo;
}
Alocação dinâmica de memória

5-Suponha dado um arquivo de texto que contém uma sequência


de números inteiros. O comprimento da sequência é desconhecido.
Escreva uma função que imprima esses números em ordem inversa
(o último, depois o penúltimo, etc.).  É claro que você terá que ler
todos os números e armazená-los na memória.  A dificuldade está
em alocar espaço para uma quantidade de números que só será
conhecida quando chegarmos ao fim do arquivo. 
Alocação dinâmica de memória

● Se a memória do computador já estiver toda ocupada, malloc não


consegue alocar mais espaço e devolve NULL. Convém verificar essa
possibilidade antes de prosseguir:

ptr = malloc (sizeof (data));


if ( ptr == NULL) {
printf ("Socorro! malloc devolveu NULL!\n");
exit (EXIT_FAILURE);
}
Alocação dinâmica de memória
● A digitação frequente e repetida desse teste é cansativa. Por isso, usaremos a seguinte
função-embalagem (= wrapper function) de malloc:

void *mallocc (size_t nbytes) {


void *ptr;
ptr = malloc ( nbytes);
if ( ptr == NULL) {
printf ("Socorro! malloc devolveu NULL!\n");
exit (EXIT_FAILURE);
}
return ptr;
}
Alocação dinâmica de memória

● O parâmetro de mallocc é do tipo size_t (abreviatura de size data type);


em muitos computadores, size_t é o mesmo que unsigned int.

● Da mesma forma, podemos preparar uma função-embalagem reallocc


para cuidar das situações em que realloc devolve NULL.
Alocação dinâmica de memória

6 -É verdade que não convém alocar blocos de poucos bytes, ou seja, invocar
malloc com argumento muito pequeno?
7-Posso alocar um vetor estaticamente com número não-constante de
elementos? Por exemplo, posso dizer
int v[ n];
se o valor de n só se torna conhecido durante a execução do programa?
8-É verdade que devemos atribiuir NULL a cada ponteiro que se tornou inútil
ou desnecessário?
9-Deveríamos usar a função calloc ao invés de malloc?