Nessa seqüência continuarei falando sobre como podemos utilizar esses ponteiros tão discriminados e a melhor forma de usar a atribuição neles. Além disso mostrarei como podemos usar ponteiros void para construirmos uma fila genérica que pode literalmente guardar qualquer tipo de dado.
Abaixo está o exemplo de um Header que fiz... Há um link para versão original
do código citado na conclusão. Ele foi feito em C++ e utilizando conceitos
Orientação a Objeto, mas não se preocupe que ele é extremamente legível para
uma pessoa que sabe C (pelo menos foi minha opinião, mas como fui eu que escrevi
não acredite! hehehe).
Vamos ao código em C, comentei algumas explicações gerais, então:
/*
Aqui temos as duas bibliotecas que precisamos para o nosso header
*/
#include <string.h> /* mem* */
#include <stdlib.h> /* malloc e free */
/*
Aqui definimos a nossa estrutura básica "nodo_basic". Ela conterá um ponteiro void, o tamanho do apontado pelo ponteiro void e um apontador para o próximo nodo.
Pode parecer estranho gravar o tamanho do que se aponta, mas é essencial. Já que não temos como saber qual tipo ele terá.
*/
typedef struct nodo_basic {
void *nodo;
size_t tam_nodo;
struct nodo_basic *next;
} nodo_basic;
/*
Nosso tipo "fila". Conterá um ponteiro pro inicio(remover nodos) e um ponteiro pro fim(inserir nodos). Elements é um contador para não termos que "correr" para sabermos quantos elementos temos na fila.
*/
typedef struct {
nodo_basic *start;
nodo_basic *end;
long int elements;
} fila;
// Se utilizar um compilador C++ podem remover as duas linhas abaixo
#define true 0
#define false 1
/*
Sempre antes de qualquer coisa chamamos esta função para limpar nosso tipo fila.
Ele já prepara nossa inserção alocando espaço para o primeiro nodo e fazendo as manipulações necessárias.
*/
void filaini( fila *aux)
{
aux->end = (nodo_basic *) malloc( sizeof(nodo_basic) ); /*cria 1° nodo*/
aux->end->nodo = NULL; /* Limpa o conteúdo do nodo */
aux->end->next = NULL;
aux->end->tam_nodo = 0;
aux->start = aux->end; /* Atribui o primeiro nodo ao inicio */
aux->elements = 0; /* Numero de elementos atuais */
}
/*
Aqui nos inserimos no tipo fila. Basicamente, alocamos espaço que precisamos e depois copiamos o que queremos para dentro do nosso nodo final e incrementamos elements.
*/
int add( fila *aux, void *x, size_t tam_x )
{
// Cria novo nodo
aux->end->next = (nodo_basic *) malloc( sizeof(nodo_basic) );
if (aux->end->next == NULL) /* testa se falta memória */
return false;
aux->end->nodo = (void *) malloc(tam_x); /* aloca memória para o nodo */
if (aux->end->nodo == NULL)
return false;
memmove(aux->end->nodo, x, tam_x); /* aux->end->nodo = X; */
aux->end->tam_nodo = tam_x;
aux->end = aux->end->next; /* coloca o novo nodo como próximo */
aux->elements++;
return true;
}
/*
Essa função elimina o nodo inicial da fila. Aqui ocorre a liberação de memória e decremento do elements para a sua eliminação. Além do inicio receber o segundo elemento da fila.
*/
int retira( fila *aux )
{
void *aux2 = aux->start;
if (aux->elements == 0)
return false;
aux->start = aux->start->next;
free( aux2 );
aux->elements--;
return true;
}
/*
Praticamente inútil já que não temos como barrar a manipulação da variável do tipo fila... O que ela faz é reinserir o nodo inicial e elimina-lo do inicio. Isso faz com que o inicio receba o segundo elemento e o antigo elemento seja posto no fim. Uma das formas de se percorrer a fila encadeada.
*/
int posindex( fila *aux, int X )
{
while ( X ) {
if (add( aux, aux->start->nodo, aux->start->tam_nodo ) == false)
return false;
retira( aux );
X--;
}
return true;
}
Esse header fiz ele adaptando um que tinha feito de C++. Durante a conversão
de C++ para C andei vendo algumas coisas e removi outras. Ótimos exemplos
são as funções: get e total. Na versão em C, elas são inúteis pois a fila
criada é acessível de qualquer lugar que a variável do tipo fila esteja.
Assim, podendo acessar diretamente o elemento inicial e/ou o total.
[2] Comentário enviado por ymc em 11/06/2004 - 08:22h
Este artigo com certeza completa o primeiro. Antes estava meio vago a utilidade do ponteiro void. Com este artigo ficou mais claro pra mim e tirou algumas duvidas sobre malloc.
Otimo artigo.
[3] Comentário enviado por robson.dantas em 13/06/2004 - 09:53h
Muito bom o seu artigo.
Tenho preparado algo sobre ponteiros void, para C++; Criei uma classe genérica, que faz acesso à dados em C++ para bancos como postgres, mySQL, SQL Server e Oracle;
[4] Comentário enviado por jllucca em 14/06/2004 - 19:43h
ymc,
certamente que completa o primeiro! Como disse no inicio do segundo, eu dividi o assunto pra deixar a parte "pratica" para ser tratada nesse artigo. Mas, para quem ler o conteúdo desse segundo artigo esta no primeiro só que mais direto e sem precisar "fritas os miolos",
[5] Comentário enviado por jllucca em 14/06/2004 - 19:45h
Robson,
sobre o que eu acho é o seguinte void é excelente para C. Mas, em C++ temos algumas coisas que nos auxiliam que podem ser até melhores que o void. No seu caso, voce já pensou em usar template? Eu não conhecia isso em C++, mas seria uma alternativa mais elegante até para a classe que coloquei na sessão scripts.
[6] Comentário enviado por engos em 25/06/2004 - 10:47h
Achei bem vago esse segundo artigo, me deixou a impressão que você correu para completar o primeiro e atropelou um pouco a teoria e deixo que o conceito prático explicasse tudo por si só.
Como você mesmo disse, é o primeiro artigo de forma prática, existiu um complementar, mas nada de muito interessante.
Gostei do primeiro artigo, mas esse segundo foi mediano, entretanto deu para perceber que você conhece bem sobre o assunto, que tal um terceiro artigo mais elaborado, com conceitos técnicos e práticos proporcionais e exemplos para serem usados no cotidiano?
Lendo esse segundo fiquei com a seguinte dúvida:
Em quesito de desempenho, onde está a vantagem?
[7] Comentário enviado por roxcorp em 02/11/2004 - 18:24h
Ola jllucca,
Fila nao eh FIFO? Quando removo um da fila ele tem que me entregar o primeiro que entrou e nao o ultimo. Isso que vc implementou acima eh uma pilha. FILO.
Abraco. Quaquer coisa me fala se eu estiver errado: tiago@roxcorp.com