William Malvezzi
Roteiro
Alocação Encadeada Linguagem C
Lista Simplesmente Encadeada Auto Avaliação
Alocação Encadeada
Parte II
Linguagem C
O padrão C ANSI define 4 funções para o sistema de alocação dinâmica, disponíveis na biblioteca stdlib.h
malloc calloc realloc free
Linguagem C - malloc
A função malloc serve para alocar memória e tem o seguinte protótipo:
void
* malloc (
unsigned
int
num);
A função toma o número de bytes que queremos alocar (num), aloca na memória e retorna um ponteiro void * para o primeiro byte alocado;
Linguagem C - malloc
O ponteiro void * pode ser atribuído a qualquer tipo de ponteiro;
Se não houver memória suficiente para alocar a
memória requisitada a função malloc() retorna um ponteiro nulo
Linguagem C - malloc
#include <stdio.h> #include <stdlib.h>
int main(int argc, char *argv[]){ int *p, a=4, i;
//Alocando memoria a numeros inteiros
p = (int *) malloc(a*sizeof(int));
//p pode ser tratado como um vetor com a posicoes
if(!p){ //se nao exite p
printf("ERRO: Memória Insuficiente!!"); exit;
}
system("PAUSE"); return 0;
Calcula o tamanho do inteiro
conforme a plaforma de HW
Linguagem C - calloc
A função calloc também serve para alocar memória, mas possui um protótipo um pouco diferente:
void * calloc (unsigned int num, unsigned int size);
A função aloca uma quantidade de memória igual a
num*size, isto é, aloca memória suficiente para um vetor
Linguagem C - calloc
Retorna um ponteiro void * para o primeiro byte alocado O ponteiro void * pode ser atribuído a qualquer tipo de
ponteiro
Se não houver memória suficiente para alocar a memória requisitada a função calloc() retorna um ponteiro nulo
Linguagem C - calloc
#include <stdio.h> #include <stdlib.h>
int main(int argc, char *argv[]){ int *p, a=4, i;
//Alocando memoria a numeros inteiros
p = (int *) calloc(a, sizeof(int));
//p pode ser tratado como um vetor com a posicoes
if(!p){ //se nao exite p
printf("ERRO: Memória Insuficiente!!"); exit;
}
system("PAUSE"); return 0;
Calcula o tamanho do inteiro
conforme a plaforma de HW
Linguagem C – realloc
A função realloc
void * realloc (void *ptr, unsigned int num);
A função realloc serve para realocar memória
A função modifica o tamanho da memória previamente alocada apontada por *ptr para o tamanho num
O valor de num pode ser maior ou menor do que o tamanho original A memória apontada pelo ptr deve ter sido alocada por malloc ou
Linguagem C – realloc
Um ponteiro para o bloco é devolvido porque realloc() pode precisar mover o bloco para aumentar seu tamanho
Se isso ocorre, o conteúdo do bloco antigo é copiado no novo bloco e nenhuma informação é perdida
Se o ponteiro for nulo, aloca num bytes e devolve um ponteiro
Se num é zero, a memória apontada por ptr é liberada Se não houver memória suficiente para a alocação.
Um ponteiro nulo é devolvido e o bloco original é deixado inalterado
Linguagem C – realloc
#include <stdio.h> #include <stdlib.h>
int main(int argc, char *argv[]){ int *p, a=30, i;
//Alocando memoria a numeros inteiros
p = (int *) malloc(a, sizeof(int));
//p pode ser tratado como um vetor com a posicoes
if(!p){ //se nao exite p
printf("ERRO: Memória Insuficiente!!"); exit;
}
Linguagem C – realloc
for (i=0; i<a ; i++) p[i] = i*i;
//O tamanho de p deve ser modificado, por algum motivo
a = 100;
p = realloc (p, a*sizeof(int)); for (i=0; i<a ; i++)
p[i] = a*i*(i-6);
system("PAUSE"); return 0; }
O programa guarda o número de bytes alocados numa
“tabela de alocação” interna
Linguagem C – realloc
Como o programa sabe a quantidade de bytes que devem ser liberados? Como o programa sabe a quantidade
Linguagem C – Alocação
Dinâmica
free()
Quando alocamos memória dinâmica é necessário que nós a liberemos quando ela não for mais necessária
void free (void *p);
Basta passar para free() o ponteiro que aponta para o início da memória alocada
Linguagem C – realloc
...
int main(int argc, char *argv[]){ int *p, a=30, i;
//Alocando memoria a numeros inteiros
p = (int *) malloc(a, sizeof(int));
//p pode ser tratado como um vetor com a posicoes
if(!p){ //se nao exite p
printf("ERRO: Memória Insuficiente!!"); exit;
}
...
free(p);
Lista Simplesmente Encadeada
Ilustração
Suponha uma estrutura para os seguintes dados:
typedef struct no{ int valor;
struct no *proximo = null; } nodo;
valor *próximo
nodo
Isto não é uma variável apenas um identificador alternativo
Lista Simplesmente Encadeada
Inicializando um ponteiro
nodo *cabeça = NULL;
*cabeça
Nulo ou vazio Nulo ou
Lista Simplesmente Encadeada
Criando um nodo para a lista
nodo *cabeça = (nodo *) malloc (sizeof(nodo));
*cabeça Valor=cobra *próximo=largat o Lixo Lixo
Lista Simplesmente Encadeada
Inicializando nodo criado
cabeca->valor = 123; cabeca->proximo = NULL;
*cabeça
Valor=123 *próximo=NULL
Lista Simplesmente Encadeada
Criando um novo nodo
nodo *noatual = NULL;
nodo *novono = NULL; *noatual
Lista Simplesmente Encadeada
Criando um novo nodo Se cabeça NULL cabeca->valor = 150; cabeca->proximo = NULL; *cabeça Valor=150 *próximo=NULL
Lista Simplesmente Encadeada
Criando um novo nodo
Se cabeça diferente de NULL
noatual = cabeca;
*cabeca
Valor=150 *próximo=NULL
Lista Simplesmente Encadeada
Criando um novo nodo
while(noatual->proximo != NULL){ noatual = noatual->proximo; } *cabeca Valor=150 *próximo= nodo1 Valor=150 *próximo= nodo2 Valor=150 *próximo= NULL
nodo nodo1 nodo2
Lista Simplesmente Encadeada
Criando um novo nodo
novono = (TProduto *) malloc(sizeof(TProduto));
*novono
Valor=cobra *próximo=largat
Lista Simplesmente Encadeada
Criando um novo nodo
novono->proximo = NULL; noatual->proximo = novono; *cabeca Valor=150 *próximo= nodo1 Valor=150 *próximo= nodo2 nodo nodo1 *noatual *novono Valor=444 *próximo =NULL nodo2
Implementação
Laboratório
Lista Simplesmente Encadeada
Uma lista encadeada é uma sequência de structs, que são os nós da lista, ligadas entre si através de ponteiros Essa sequência pode ser acessada através de um
ponteiro para o primeiro nó (cabeça da lista - head)
Cada nó contém um ponteiro que aponta para a struct que é a sucessora na lista
O ponteiro da última struct (calda da lista - tail) aponta para NULL, indicando o fim da lista
Lista Simplesmente Encadeada
Essa estrutura é criada dinamicamente na memória Utilizando malloc() e free()
Tornando-se simples introduzir, retirar e ordenar nós na lista
Cenário:
Supondo que queremos criar uma lista encadeada para armazenar os produtos disponíveis em uma loja
Lista Simplesmente Encadeada
Criando o nó
struct Produto {
int codigo; //Codigo do produto
double preco; //Preco do produto
struct Produto *proximo; //Proximo elemento da lista //encadeada de Produtos
Lista Simplesmente Encadeada
include <stdio.h> Include <stdlib.h>
//Estrutura que sera usada p/ criar os nós da lista
typedef struct tipo_Produto {
int codigo; //Codigo do produto
double preco; //Preco do produto
struct tipo_Produto *proximo; //Proximo elemento //da lista encadeada de Produtos
Lista Simplesmente Encadeada
//Lista todos os elementos presentes na lista encadeada
void listar (TProduto *noatual){ int i=0;
while( noatual != NULL ){
i++;
printf("\n\nProduto numero %d\nCodigo: %d\nPreco: R$%.2lf",i, noatual->codigo, noatual->preco);
//Faz noatual apontar para o proximo no
noatual = noatual->proximo; }
Lista Simplesmente Encadeada
//Funcao para inserir um novo no, ao final da lista
void inserir (TProduto **cabeca){ TProduto *noatual, *novono; int cod;
double preco;
printf("\n Codigo do novo produto: "); scanf("%d", &cod);
printf("\n Preco do produto:R$"); scanf("%lf", &preco);
Lista Simplesmente Encadeada
// Se ainda nao existe nenhum produto na lista
if (*cabeca == NULL){ //cria o no cabeca
*cabeca = (TProduto *) malloc(sizeof(TProduto)); (*cabeca)->codigo = cod;
(*cabeca)->preco = preco; (*cabeca)->proximo = NULL; } else{
//Se ja existem elementos na lista, deve percorre-la ate' o seu final e inserir o novo elemento
Lista Simplesmente Encadeada
noatual = *cabeca;
while(noatual->proximo != NULL)
//Ao final do while, noatual aponta para o ultimo no
noatual = noatual->proximo;
//Aloca memoria para o novo no
novono = (TProduto *) malloc(sizeof(TProduto)); novono->codigo = cod;
novono->preco = preco; novono->proximo = NULL;
//Faz o ultimo no apontar para o novo no
Lista Simplesmente Encadeada
int main(int argc, char *argv[]){
//Ponteiro para a cabeca da lista
TProduto *cabeca = NULL; TProduto *noatual = NULL;
//Caractere para receber a opcao do usuario
char q; do {
printf("\n\nOpcoes: \nI -> para inserir novo produto;\nL -> para listar os produtos; \nS -> para sair \n:");
Lista Simplesmente Encadeada
switch(q) {
case 'i': case 'I':
//passa o end p/ alterar o ptr (por referencia)
inserir(&cabeca); break; case 'l': case 'L':
//passa o ptr, pois nao havera alteracao (por valor)
listar(cabeca); break; case 's': case 'S':
break;
default:
Lista Simplesmente Encadeada
flush(stdin); //Limpa o buffer de entrada
} while ((q != 's') && (q != 'S') );
//Desaloca a memoria alocada para os elementos da lista
noatual = cabeca;
while (noatual != NULL){
cabeca = noatual->proximo; free(noatual);
noatual = cabeca; }
REFERÊNCIAS
RODRIGUES, R.F., Estrutura de Dados e Algoritmos –
Notas de aula. UFAM. 2000
FURGERI. S., Listas Lineares. Apontamentos de Aula www.gomeshp.com