elhacker.net cabecera Bienvenido(a), Visitante. Por favor Ingresar o Registrarse
¿Perdiste tu email de activación?.

 

 


Tema destacado: Entrar al Canal Oficial Telegram de elhacker.net


+  Foro de elhacker.net
|-+  Programación
| |-+  Programación C/C++ (Moderadores: Eternal Idol, Littlehorse, K-YreX)
| | |-+  Pregunta sobre estructuras de datos genericas.
0 Usuarios y 1 Visitante están viendo este tema.
Páginas: [1] Ir Abajo Respuesta Imprimir
Autor Tema: Pregunta sobre estructuras de datos genericas.  (Leído 3,524 veces)
astinx

Desconectado Desconectado

Mensajes: 111



Ver Perfil
Pregunta sobre estructuras de datos genericas.
« en: 18 Marzo 2012, 20:29 pm »

Hola, tengo una duda acerca de estructuras de datos genéricas, como por ejemplo, una lista. Hacer una lista genérica que contenga diferentes tipos de datos básicos, como int, char, char* o float es sencillo; definimos un puntero a void y luego por ejemplo si queremos imprimir la lista entera bajo diferentes criterios usamos punteros a funciones que casteen el puntero al tipo adecuado de puntero. Sin embargo, si tenemos una lista genérica que adicionalmente, además de los tipos mencionados anteriormente, contiene una estructura, como por ejemplo t_Persona, que contiene los campos nombre y apellido, ambos char*, ¿Como deberíamos proceder para hacer un puntero a función que lo imprima de manera adecuada?.

Osea mi problema es que yo quiero tener una lista genérica de esa forma, tener una función imprimir que reciba la lista y un puntero a función, donde la función a la que apunta es el criterio a usar. Si yo en mi lista tengo 2, 4, a, c, 'Hola mundo!', 3.45, t_Persona(nombre: 'Jorge' apellido:'Ruiz') (Disculpen la notación de este ultimo), entonces si yo llamara a la función imprimir y le pasara la lista y la función que castea a caracteres me imprimiría: (El ASCII de 2), (El ASCII de 4), a, c, H, (Basura), (Mas basura).

Mi punto es: Si quiero imprimir usando el criterio para imprimir una persona, voy a tener que castear los punteros a void a punteros a t_Persona, con un dato que realmente sea de t_Persona no va a haber problema, sin embargo cuando este iterando y me cruce un puntero que en realidad es un puntero a float, y lo castee a tipo persona, y trate de acceder a sus miembros, esto me va a tirar un Segmentation Fault con toda la razón.

Yo pensé, entonces simplemente tendría que exigir que el resto de los elementos, como mínimo, ocupen la misma cantidad de bytes que t_Persona, de esa manera cuando los castee, me devolverán basura, pero no me tirara Segmentation Fault.

Mi duda es simple: ¿Existe una manera mas limpia de lograr mi objetivo?

Les dejo un ejemplo de mi codigo:

Código
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3.  
  4. typedef struct t_Persona {
  5. char* nombre;
  6. char* apellido;
  7. } t_Persona;
  8.  
  9. //Decimos que un puntero a void es sinonimo de una direccion.
  10. typedef void* t_Direccion;
  11.  
  12. typedef struct t_Lista {
  13. t_Direccion* dato;
  14. //El size NO lo necesitamos simplemente para saber cuantos elementos tenemos, SI lo necesitamos para seguirle la pista
  15. //A cuanto espacio tenemos que alocar.
  16. int size;
  17. } t_Lista;
  18.  
  19. //El tipo iterador contiene la lista y la posicion actual dentro de ella
  20. typedef struct t_Iterador {
  21. t_Lista* lista;
  22. //Nodo actual para recorrer
  23. int actual;
  24. } t_Iterador;
  25.  
  26. t_Iterador tIterador_Crear () {
  27. t_Iterador nue;
  28. nue.lista= (t_Lista*) malloc (sizeof(t_Lista));
  29. (nue.lista)->size=0;
  30. (nue.lista)->dato=NULL;
  31. nue.actual=0;
  32. return nue;
  33. }
  34.  
  35. void tIterador_Iniciar(t_Iterador* iter) {
  36. iter->actual=0;
  37. }
  38.  
  39. /* Notese la diferencia entre el crear y el iniciar; El crear nos crea una nueva instancia, y el iniciar
  40.  * prepara el iterador para iterar, recibiendo la lista sobre la cual va a trabajar y poniendo su posicion
  41.  * actual a cero. */
  42.  
  43. /*Un simple agregar al final*/
  44.  
  45. void tIterador_Agregar (t_Iterador* iter, t_Direccion i) {
  46. if (iter->lista->size == 0) {
  47. iter->lista->dato = (t_Direccion*) malloc (sizeof(t_Direccion)*(++iter->lista->size));
  48. } else {
  49. iter->lista->dato = (t_Direccion*) realloc (iter->lista->dato, sizeof(t_Direccion)*(++iter->lista->size));
  50. }
  51. iter->lista->dato[iter->actual++] = i;
  52. }
  53.  
  54. /*Funciones que imprimen en diferentes formatos, utilizadas para el imprimir*/
  55.  
  56. void imprimirEnteros (t_Direccion x) {
  57. printf("%i, ",*((int*)(x)));
  58. }
  59.  
  60. void imprimirCaracteres (t_Direccion x) {
  61. printf("%c, ",*((char*)(x)));
  62. }
  63.  
  64. void imprimirStrings (t_Direccion x) {
  65. printf("%s, ",((char*)(x)));
  66. }
  67.  
  68. /* No escatimes en el uso del parentesis en estos casos!!! */
  69. /* void imprimirPersonas (t_Direccion x) {
  70. printf("%s %s, ",((t_Persona*)(x))->nombre, ((t_Persona*)(x))->apellido);
  71. } */
  72. /* En estos casos hay que asegurarse de que todos los elementos tienen el mismo tamaño*/
  73.  
  74. /*El imprimir generico*/
  75. /*Nomenclatura de una funcion pasada como parametro a otra (puntero a funcion)
  76.  *TIPORETORNO (*NOMBRE)(PARAMETROS) Notese que para un puntero a funcion el asterisco se usa a la izquierda*/
  77. void tIterador_Imprimir (t_Iterador* iter, void (*criterio)(t_Direccion)) {
  78. criterio(iter->lista->dato[iter->actual]); /*Modo de uso de un puntero a funcion*/
  79. }
  80.  
  81. int tIterador_Fin (t_Iterador* iter) {
  82. return (iter->actual < iter->lista->size)?(1):(0);
  83. }
  84.  
  85. void tIterador_Avanzar (t_Iterador* iter) {
  86. iter->actual++;
  87. }
  88.  
  89. int main(int argc, char** argv)
  90. {
  91.  
  92. int a=65, b=66, c='a', d=68, e='c';
  93. char* f = "Holaaa";
  94. t_Iterador iter = tIterador_Crear();
  95.  
  96. tIterador_Iniciar(&iter);
  97.  
  98. /*Vamos a agregar los numeros del 65 al 70*/
  99. tIterador_Agregar(&iter, &a);
  100. tIterador_Agregar(&iter, &b);
  101. tIterador_Agregar(&iter, &c);
  102. tIterador_Agregar(&iter, &d);
  103. tIterador_Agregar(&iter, &e);
  104. tIterador_Agregar(&iter, f); //Look!
  105.  
  106. /*Imprimimos como enteros*/
  107. tIterador_Iniciar(&iter);
  108. /*Al imprimir le pasamos la funcion que va a usar como criterio de conversion*/
  109. while ((tIterador_Fin(&iter))) {
  110. tIterador_Imprimir(&iter, imprimirEnteros);
  111. tIterador_Avanzar(&iter);
  112. }
  113. printf("\n");
  114. /*Imprimimos como Caracteres*/
  115. tIterador_Iniciar(&iter);
  116. /*Al imprimir le pasamos la funcion que va a usar como criterio de conversion*/
  117. while ((tIterador_Fin(&iter))) {
  118. tIterador_Imprimir(&iter, imprimirCaracteres);
  119. tIterador_Avanzar(&iter);
  120. }
  121. printf("\n");
  122. /*Imprimimos como Strings*/
  123. tIterador_Iniciar(&iter);
  124. /*Al imprimir le pasamos la funcion que va a usar como criterio de conversion*/
  125. while ((tIterador_Fin(&iter))) {
  126. tIterador_Imprimir(&iter, imprimirStrings);
  127. tIterador_Avanzar(&iter);
  128. }
  129.  
  130. return 0;
  131. }

Si usaramos el imprimirPersonas obviamente nos tiraría un segmentation fault.

Muchas gracias por detenerse a leer, y saludos!


En línea

La programación hoy en día es una carrera entre los ingenieros de software intentando construir mejores y más eficientes programas a prueba de idiotas y el Universo intentando producir mejores y más grandes idiotas. De momento, el Universo está ganando
Gallu

Desconectado Desconectado

Mensajes: 247



Ver Perfil
Re: Pregunta sobre estructuras de datos genericas.
« Respuesta #1 en: 18 Marzo 2012, 23:45 pm »

Lo único que se me ocurre es que a la lista, en lugar de guardar directamente el dato,   encapsules los mismo en un tipo de dato que contenga un puntero a función , dicha función será la que llamarás cuando intentes imprimir el valor del nodo en el que te encuentras , eje
Código
  1. typedef struct  nodoGenerico{
  2. t_Direccion dato;
  3. char * ( * toString)();
  4. } nodoGenerico;
  5.  
antes de agregar el nodoGenerico a la lista, deberás proporcionar la función que describirá al objeto apuntado por dato, si no lo haces, has de suponer que es un tipo de dato simple e imprimirlo como proceda .

Saludos


En línea

Nadie alcanza la meta con un solo intento, ni perfecciona la vida con una sola rectificación, ni alcanza altura con un solo vuelo.
astinx

Desconectado Desconectado

Mensajes: 111



Ver Perfil
Re: Pregunta sobre estructuras de datos genericas.
« Respuesta #2 en: 20 Marzo 2012, 00:13 am »

Gracias, había pensado algo parecido, pero no tuve en cuenta el puntero a función, voy a intentarlo y después te digo como salio xD

Saludos!
En línea

La programación hoy en día es una carrera entre los ingenieros de software intentando construir mejores y más eficientes programas a prueba de idiotas y el Universo intentando producir mejores y más grandes idiotas. De momento, el Universo está ganando
Páginas: [1] Ir Arriba Respuesta Imprimir 

Ir a:  

Mensajes similares
Asunto Iniciado por Respuestas Vistas Último mensaje
pregunta sobre winsock y envio de datos
Programación Visual Basic
Sai-To 4 1,989 Último mensaje 19 Enero 2008, 02:12 am
por vivachapas
ADT estructuras de datos
Programación C/C++
do-while 4 7,613 Último mensaje 3 Julio 2010, 13:11 pm
por O-LLOS-O
Problema al usar Listas Genericas y Acceso a datos
.NET (C#, VB.NET, ASP)
israelchris 1 5,167 Último mensaje 27 Agosto 2010, 23:01 pm
por [D4N93R]
pregunta sobre como ver los datos de un frame a otro en Netbeans
Java
XpandyX 0 3,187 Último mensaje 8 Marzo 2011, 17:56 pm
por XpandyX
[Estructuras de Datos] Algoritmo de Prim y su ruta mas corta
Programación General
Wacherax 4 6,251 Último mensaje 17 Noviembre 2012, 18:02 pm
por Hadess_inf
WAP2 - Aviso Legal - Powered by SMF 1.1.21 | SMF © 2006-2008, Simple Machines