Autor
|
Tema: Listas generales en C (Leído 3,366 veces)
|
Fedex15
Desconectado
Mensajes: 7
|
Hola, estoy tratando de resolver un problema que se me pide con listas. Debo usar listas siguiendo la sig estructura: typedef struct _GNodo { void *dato; struct _GNodo *sig; } GNodo;
Tengo 3 archivos, el glist.h, glist.c, y main_g.c. Las funciones que tengo son las basicas, que me permiten crear, destruir, agregar final, agregar inicio, y recorrer. #include "glist.h" #include <stdlib.h> GList glist_crear() { return NULL; } void glist_destruir(GList lista) { GList nodoAEliminar; while (lista != NULL) { nodoAEliminar = lista; lista = lista->sig; } } GList glist_agregar_inicio(GList lista, void* dato) { GList nuevoNodo = malloc (sizeof (GNodo )); nuevoNodo->dato = dato; nuevoNodo->sig = lista; return nuevoNodo; } GList glist_agregar_final (GList lista, void* dato) { GList nuevoNodo = malloc (sizeof (GNodo )); nuevoNodo->dato = dato; nuevoNodo->sig = NULL; if (lista == NULL) { return nuevoNodo; } GList nodo = lista; for (; nodo->sig != NULL; nodo = nodo->sig); nodo->sig = nuevoNodo; return lista; } void glist_recorrer (GList lista, FuncionVisitante visit) { for (GList nodo = lista; nodo != NULL; nodo=nodo->sig){ visit (nodo->dato); } }
El problema que estoy teniendo, es que ahora no estoy trabajando con listas donde el dato es un int, estoy trabajando con listas donde el dato es un puntero a void. Yo se que el puntero a void puede apuntar a cualquier tipo de dato, pero para poder desreferenciarlo tengo que aplicar el cast correspondiente al tipo de dato que guarda. int main(){ int a = 3; void *ptr; ptr = &a; printf ("%d", *((int*)ptr )); //convierto ptr a int* y lo desreferencio con * return 0; }
Este es el main que tengo: #include <stdio.h> #include <stdlib.h> #include <string.h> #include "glist.h" static void imprimir_entero(void* dato) { } int main(){ int a = 3; char c = 'a'; double d = 2.3; GList lista = glist_crear(); lista = glist_agregar_inicio (lista, &a); lista = glist_agregar_inicio (lista, &c); lista = glist_agregar_inicio (lista, &d); lista = glist_agregar_final (lista, &a); printf ("%lf %c %d\n", (*(double*)lista ->dato ),(*(char*)lista ->sig ->dato ),(*(int*)lista ->sig ->sig ->sig ->dato ) ); //~ printf ("\n %lf", (*(double*)(lista->dato))); glist_recorrer (lista, imprimir_entero); glist_destruir (lista); return 0; }
Como podria hacer para poder saber cual es el tipo de dato al que apunta void. Como podria hacer lo que esta en la linea 20 printf ("%lf %c %d\n", (*(double*)lista ->dato ),(*(char*)lista ->sig ->dato ),(*(int*)lista ->sig ->sig ->sig ->dato ) );
de forma general con la funcion imprimir_entero. El primer caso seria con un entero, un double y un char o cadena. Gracias
|
|
|
En línea
|
|
|
|
MAFUS
Desconectado
Mensajes: 1.603
|
He intentado compilar el código y tiene muchos errores. Podría resolverlos pero, la verdad, me ha dado pereza. Si pudieras corregir el código para que no haya mas errores que el lógico que intentas resolver sería de agradecer.
|
|
|
En línea
|
|
|
|
Fedex15
Desconectado
Mensajes: 7
|
He intentado compilar el código y tiene muchos errores. Podría resolverlos pero, la verdad, me ha dado pereza. Si pudieras corregir el código para que no haya mas errores que el lógico que intentas resolver sería de agradecer.
Gracias por responder, aca te dejo todo el codigo en un solo archivo: #include <stdio.h> #include <stdlib.h> #include <stddef.h> typedef struct _GNodo { void *dato; struct _GNodo *sig; } GNodo; typedef GNodo* GList; typedef void (*FuncionVisitante) (void* dato); GList glist_crear() { return NULL; } void glist_destruir(GList lista) { GList nodoAEliminar; while (lista != NULL) { nodoAEliminar = lista; lista = lista->sig; } } GList glist_agregar_inicio(GList lista, void* dato) { GList nuevoNodo = malloc (sizeof (GNodo )); nuevoNodo->dato = dato; nuevoNodo->sig = lista; return nuevoNodo; } GList glist_agregar_final (GList lista, void* dato) { GList nuevoNodo = malloc (sizeof (GNodo )); nuevoNodo->dato = dato; nuevoNodo->sig = NULL; if (lista == NULL) { return nuevoNodo; } GList nodo = lista; for (; nodo->sig != NULL; nodo = nodo->sig); nodo->sig = nuevoNodo; return lista; } void glist_recorrer (GList lista, FuncionVisitante visit) { for (GList nodo = lista; nodo != NULL; nodo=nodo->sig){ visit (nodo->dato); } } static void imprimir_entero(void* dato) { } // Lo que yo quiero hacer es algo asi, pero no se como hacerlo: // Si es entero: // printf ("%d ", (*(int*)dato)); // Si es double: // printf ("%lf ", (*(double*)dato)); // Si es cadena: // printf ("%s ", (*(char*)dato)); // Como tendria que hacer para saber de alguna forma cual es el tipo // que esta apuntando el puntero. int main(){ int a = 3; char c = 'a'; double d = 2.3; GList lista = glist_crear(); lista = glist_agregar_inicio (lista, &a); lista = glist_agregar_inicio (lista, &c); lista = glist_agregar_inicio (lista, &d); lista = glist_agregar_final (lista, &a); printf ("%lf %c %d\n", (*(double*)lista ->dato ),(*(char*)lista ->sig ->dato ),(*(int*)lista ->sig ->sig ->sig ->dato ) ); glist_recorrer (lista, imprimir_entero); glist_destruir (lista); return 0; }
yo lo compilo usando gcc listas.c -o lista, asi me funciona bien. PD: Aca te dejo unas modificaciones que estuve haciendo, haber si voy por buen camino. #include <stdio.h> #include <stdlib.h> #include <stddef.h> #define ENTERO 0 #define DOUBLE 1 #define CADENA 2 typedef struct _variante{ int tipo; void* valor; } variante; typedef variante* dato; typedef struct _GNodo { void *dato; struct _GNodo *sig; } GNodo; typedef GNodo* GList; typedef void (*FuncionVisitante) (dato d); dato dato_crear (){ dato nuevoDato = (variante *) malloc (sizeof(variante )); return nuevoDato; } void dato_insertar (dato datos, int tipo, void* d){ datos->tipo = tipo; datos->valor = d; } void glist_destruir(GList lista) { GList nodoAEliminar; while (lista != NULL) { nodoAEliminar = lista; lista = lista->sig; } } GList glist_crear() { return NULL; } GList glist_agregar_inicio(GList lista, void* dato) { GList nuevoNodo = malloc (sizeof (GNodo )); nuevoNodo->dato = dato; nuevoNodo->sig = lista; return nuevoNodo; } GList glist_agregar_final (GList lista, void* dato) { GList nuevoNodo = malloc (sizeof (GNodo )); nuevoNodo->dato = dato; nuevoNodo->sig = NULL; if (lista == NULL) { return nuevoNodo; } GList nodo = lista; for (; nodo->sig != NULL; nodo = nodo->sig); nodo->sig = nuevoNodo; return lista; } void glist_recorrer (GList lista, FuncionVisitante visit) { for (GList nodo = lista; nodo != NULL; nodo=nodo->sig){ visit (nodo->dato); } } static void imprimir_entero(dato d) { switch (d->tipo){ case (0): printf ("%d ", *(int*)d ->valor ); break; case (1): printf ("%lf ", *(double*)d ->valor ); break; case (2): printf ("%s ", (char*)d ->valor ); break; } } // Lo que yo quiero hacer es algo asi, pero no se como hacerlo: // Si es entero: // printf ("%d ", (*(int*)dato)); // Si es double: // printf ("%lf ", (*(double*)dato)); // Si es cadena: // printf ("%s ", (*(char*)dato)); // Como tendria que hacer para saber de alguna forma cual es el tipo // que esta apuntando el puntero. int main(){ int b = 3; double num = 6.7; char cadena[50] = "mundo "; dato general = dato_crear(); dato general2 = dato_crear(); dato general3 = dato_crear(); dato_insertar(general, ENTERO, &b); dato_insertar(general2, DOUBLE, &num); dato_insertar(general3, CADENA, cadena); GList lista = glist_crear(); lista = glist_agregar_inicio (lista, general); lista = glist_agregar_inicio (lista, general2); lista = glist_agregar_inicio (lista, general3); //~ lista = glist_agregar_final (lista, &a); glist_recorrer (lista, imprimir_entero); glist_destruir (lista); return 0; }
|
|
« Última modificación: 21 Abril 2017, 15:44 pm por Fedex15 »
|
En línea
|
|
|
|
|
CalgaryCorpus
|
Cuando estas insertando, en estos momentos, con el codigo que presentas, indicas explicitamente el tipo de dato que esta siendo guardado., por ejemplo: dato_insertar(general, ENTERO, &b); dato_insertar(general2, DOUBLE, &num); dato_insertar(general3, CADENA, cadena);
luego te obligas a hacer un switch con ese tipo. Tengo una solucion que elimina el switch posterior, aunque aun tienes que indicar el tipo de dato que usas al insertar. Sugiero crear un nuevo campo que guarde un puntero a una funcion que sepa imprimir el dato que estas agregando. typedef struct _variante{ int tipo; void* valor; void (*f)(void *); } variante;
definir las funciones que saben imprimir, por ejemplo: void tipo_entero(void * pTipo) { printf("%d", *(int *)pTipo ); }
Las otras funciones son similares, pero usan otros %d en el printf y otro cast. luego en dato_insertar simplemente se copia el puntero a funcion void dato_insertar (dato datos, int tipo, void* d, void (*f)() ){ datos->tipo = tipo; datos->valor = d; datos->f = f; }
y esta funcion se invoca usando el nombre de la funcion a usar para imprimr. Nota que es solo el nombre de la funcion, No como siempre usas las funciones, con parentesis. dato_insertar(general, &b, tipo_entero );
y finalmente cuando quieras imprimir el dato, solo haces y esto imprimira de acuerdo a la funcion que usaste. Suerte!
|
|
|
En línea
|
|
|
|
Fedex15
Desconectado
Mensajes: 7
|
Cuando estas insertando, en estos momentos, con el codigo que presentas, indicas explicitamente el tipo de dato que esta siendo guardado., por ejemplo: dato_insertar(general, ENTERO, &b); dato_insertar(general2, DOUBLE, &num); dato_insertar(general3, CADENA, cadena);
luego te obligas a hacer un switch con ese tipo. Tengo una solucion que elimina el switch posterior, aunque aun tienes que indicar el tipo de dato que usas al insertar. Sugiero crear un nuevo campo que guarde un puntero a una funcion que sepa imprimir el dato que estas agregando. typedef struct _variante{ int tipo; void* valor; void (*f)(void *); } variante;
definir las funciones que saben imprimir, por ejemplo: void tipo_entero(void * pTipo) { printf("%d", *(int *)pTipo ); }
Las otras funciones son similares, pero usan otros %d en el printf y otro cast. luego en dato_insertar simplemente se copia el puntero a funcion void dato_insertar (dato datos, int tipo, void* d, void (*f)() ){ datos->tipo = tipo; datos->valor = d; datos->f = f; }
y esta funcion se invoca usando el nombre de la funcion a usar para imprimr. Nota que es solo el nombre de la funcion, No como siempre usas las funciones, con parentesis. dato_insertar(general, &b, tipo_entero );
y finalmente cuando quieras imprimir el dato, solo haces y esto imprimira de acuerdo a la funcion que usaste. Suerte! Gracias por la respuesta, voy a ver que me sale. Ahora estoy haciendo un menu que me pidieron usando listas generales para crear listas de enteros.
|
|
|
En línea
|
|
|
|
CalgaryCorpus
|
La firma de la funcion modificada que propuse esta mala, o incompleta. Dice void dato_insertar (dato datos, int tipo, void* d, void (*f)() ){ deberia decir void dato_insertar (dato datos, void* d, void (*f)(void *) ){
|
|
|
En línea
|
|
|
|
|
Mensajes similares |
|
Asunto |
Iniciado por |
Respuestas |
Vistas |
Último mensaje |
|
|
Soldaditos y generales.
Diseño Gráfico
|
APOKLIPTICO
|
1
|
1,851
|
30 Marzo 2006, 14:08 pm
por ranslsad
|
|
|
Arboles generales
Java
|
kattysol7
|
2
|
7,717
|
7 Mayo 2010, 01:00 am
por kattysol7
|
|
|
Uso de Listas: Subprograma que lea 2 listas y forme una.
Dudas Generales
|
hbenitez
|
2
|
3,588
|
8 Agosto 2010, 20:11 pm
por hbenitez
|
|
|
Ayuda Acerca De Listas y Listas Circulares (Revienta Memoria :S)
Programación C/C++
|
Gerik
|
0
|
6,113
|
12 Septiembre 2010, 01:49 am
por Gerik
|
|
|
Dudas Generales proxy
Redes
|
maxpowersi
|
2
|
2,862
|
17 Septiembre 2012, 17:54 pm
por el-brujo
|
|