Ponteiros void na linguagem C (parte 2)

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.

[ Hits: 57.543 ]

Por: Ricardo Rodrigues Lucca em 09/06/2004 | Blog: http://aventurasdeumdevop.blogspot.com.br/


Fila



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.

Página anterior     Próxima página

Páginas do artigo
   1. Introdução
   2. Atribuição
   3. Teoria do void
   4. Fila
   5. Concluindo
Outros artigos deste autor

VIM avançado (parte 1)

Conceitos sobre o X-Window

Ponteiros void na linguagem C

Introdução à linguagem C - Parte III

Introdução à linguagem C - Parte IV

Leitura recomendada

Brincando com o editor HT

LivreNFE - O emissor Nfe open source para Linux

Substituindo a biblioteca conio.h no Linux usando ncurses curses.h

Introdução à plataforma GNU de desenvolvimento

Utilizando a biblioteca NCURSES - Parte III

  
Comentários
[1] Comentário enviado por lorenzi em 10/06/2004 - 00:26h

muito bom o artigo para quem ja programa ou que esta comecando a usar a linguagem C.

[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;

o que acha sobre o assunto ?

--
Robson

[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",

[]'s

[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.

[]'s

[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: [email protected]

Tiago

[8] Comentário enviado por jllucca em 07/11/2004 - 20:22h

Olá,

Estou me comunicando com o roxcorp por email,

mas o programa da pagina quatro está correto. Acabei de testa-lo aqui e ele realiza um FIFO e não um FILO como ele alega.

A lista: 0 1 2 3 4

Ao ser removido dois elementos ficou: 2 3 4

Em FILO, seria: 0 1 2
Mas, não aconteceu. :-)

Como disse, estou falando por email com ele para vermos esse impasse.

[]'s

[9] Comentário enviado por kernel_sys em 10/10/2005 - 13:40h

Muito bom artigo mesmo , parabens


Contribuir com comentário