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
#include <stdio.h> #include <stdlib.h> typedef struct t_Persona { char* nombre; char* apellido; } t_Persona; //Decimos que un puntero a void es sinonimo de una direccion. typedef void* t_Direccion; typedef struct t_Lista { t_Direccion* dato; //El size NO lo necesitamos simplemente para saber cuantos elementos tenemos, SI lo necesitamos para seguirle la pista //A cuanto espacio tenemos que alocar. int size; } t_Lista; //El tipo iterador contiene la lista y la posicion actual dentro de ella typedef struct t_Iterador { t_Lista* lista; //Nodo actual para recorrer int actual; } t_Iterador; t_Iterador tIterador_Crear () { t_Iterador nue; (nue.lista)->size=0; (nue.lista)->dato=NULL; nue.actual=0; return nue; } void tIterador_Iniciar(t_Iterador* iter) { iter->actual=0; } /* Notese la diferencia entre el crear y el iniciar; El crear nos crea una nueva instancia, y el iniciar * prepara el iterador para iterar, recibiendo la lista sobre la cual va a trabajar y poniendo su posicion * actual a cero. */ /*Un simple agregar al final*/ void tIterador_Agregar (t_Iterador* iter, t_Direccion i) { if (iter->lista->size == 0) { } else { iter->lista->dato = (t_Direccion*) realloc (iter->lista->dato, sizeof(t_Direccion)*(++iter->lista->size)); } iter->lista->dato[iter->actual++] = i; } /*Funciones que imprimen en diferentes formatos, utilizadas para el imprimir*/ void imprimirEnteros (t_Direccion x) { } void imprimirCaracteres (t_Direccion x) { } void imprimirStrings (t_Direccion x) { } /* No escatimes en el uso del parentesis en estos casos!!! */ /* void imprimirPersonas (t_Direccion x) { printf("%s %s, ",((t_Persona*)(x))->nombre, ((t_Persona*)(x))->apellido); } */ /* En estos casos hay que asegurarse de que todos los elementos tienen el mismo tamaño*/ /*El imprimir generico*/ /*Nomenclatura de una funcion pasada como parametro a otra (puntero a funcion) *TIPORETORNO (*NOMBRE)(PARAMETROS) Notese que para un puntero a funcion el asterisco se usa a la izquierda*/ void tIterador_Imprimir (t_Iterador* iter, void (*criterio)(t_Direccion)) { criterio(iter->lista->dato[iter->actual]); /*Modo de uso de un puntero a funcion*/ } int tIterador_Fin (t_Iterador* iter) { return (iter->actual < iter->lista->size)?(1):(0); } void tIterador_Avanzar (t_Iterador* iter) { iter->actual++; } int main(int argc, char** argv) { int a=65, b=66, c='a', d=68, e='c'; char* f = "Holaaa"; t_Iterador iter = tIterador_Crear(); tIterador_Iniciar(&iter); /*Vamos a agregar los numeros del 65 al 70*/ tIterador_Agregar(&iter, &a); tIterador_Agregar(&iter, &b); tIterador_Agregar(&iter, &c); tIterador_Agregar(&iter, &d); tIterador_Agregar(&iter, &e); tIterador_Agregar(&iter, f); //Look! /*Imprimimos como enteros*/ tIterador_Iniciar(&iter); /*Al imprimir le pasamos la funcion que va a usar como criterio de conversion*/ while ((tIterador_Fin(&iter))) { tIterador_Imprimir(&iter, imprimirEnteros); tIterador_Avanzar(&iter); } /*Imprimimos como Caracteres*/ tIterador_Iniciar(&iter); /*Al imprimir le pasamos la funcion que va a usar como criterio de conversion*/ while ((tIterador_Fin(&iter))) { tIterador_Imprimir(&iter, imprimirCaracteres); tIterador_Avanzar(&iter); } /*Imprimimos como Strings*/ tIterador_Iniciar(&iter); /*Al imprimir le pasamos la funcion que va a usar como criterio de conversion*/ while ((tIterador_Fin(&iter))) { tIterador_Imprimir(&iter, imprimirStrings); tIterador_Avanzar(&iter); } return 0; }
Si usaramos el imprimirPersonas obviamente nos tiraría un segmentation fault.
Muchas gracias por detenerse a leer, y saludos!