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


 


Tema destacado: 4n4lDetector v1.3: herramienta de análisis estático de malware


+  Foro de elhacker.net
|-+  Programación
| |-+  Programación C/C++ (Moderadores: Eternal Idol, Littlehorse)
| | |-+  Listas generales en C
0 Usuarios y 1 Visitante están viendo este tema.
Páginas: [1] Ir Abajo Respuesta Imprimir
Autor Tema: Listas generales en C  (Leído 722 veces)
Fedex15

Desconectado Desconectado

Mensajes: 7


Ver Perfil
Listas generales en C
« en: 21 Abril 2017, 00:25 »

Hola, estoy tratando de resolver un problema que se me pide con listas. Debo usar listas siguiendo la sig estructura:

Código
  1. typedef struct _GNodo {
  2. void *dato;
  3. struct _GNodo *sig;
  4. } 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.

Código
  1. #include "glist.h"
  2. #include <stdlib.h>
  3.  
  4. GList glist_crear() {
  5. return NULL;
  6. }
  7.  
  8. void glist_destruir(GList lista) {
  9. GList nodoAEliminar;
  10. while (lista != NULL) {
  11. nodoAEliminar = lista;
  12. lista = lista->sig;
  13. free (nodoAEliminar);
  14. }
  15. }
  16.  
  17. GList glist_agregar_inicio(GList lista, void* dato) {
  18. GList nuevoNodo = malloc (sizeof (GNodo));
  19. nuevoNodo->dato = dato;
  20. nuevoNodo->sig = lista;
  21. return nuevoNodo;
  22. }
  23.  
  24. GList glist_agregar_final (GList lista, void* dato) {
  25. GList nuevoNodo = malloc (sizeof (GNodo));
  26. nuevoNodo->dato = dato;
  27. nuevoNodo->sig = NULL;
  28. if (lista == NULL) {
  29. return nuevoNodo;
  30. }
  31. GList nodo = lista;
  32. for (; nodo->sig != NULL; nodo = nodo->sig);
  33. nodo->sig = nuevoNodo;
  34. return lista;
  35. }
  36.  
  37. void glist_recorrer (GList lista, FuncionVisitante visit) {
  38. for (GList nodo = lista; nodo != NULL; nodo=nodo->sig){
  39. visit (nodo->dato);
  40. }
  41. }
  42.  

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.

Código
  1. int main(){
  2. int a = 3;
  3. void *ptr;
  4. ptr = &a;
  5. printf ("%d", *((int*)ptr)); //convierto ptr a int* y lo desreferencio con *
  6. return 0;
  7. }
  8.  

Este es el main que tengo:

Código
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include "glist.h"
  5.  
  6.  
  7. static void imprimir_entero(void* dato) {
  8.  printf("%d ", (*(int*)dato));
  9. }
  10.  
  11. int main(){
  12. int a = 3;
  13. char c = 'a';
  14. double d = 2.3;
  15. GList lista = glist_crear();
  16. lista = glist_agregar_inicio (lista, &a);
  17. lista = glist_agregar_inicio (lista, &c);
  18. lista = glist_agregar_inicio (lista, &d);
  19. lista = glist_agregar_final (lista, &a);
  20. printf ("%lf %c %d\n", (*(double*)lista->dato),(*(char*)lista->sig->dato),(*(int*)lista->sig->sig->sig->dato) );
  21. //~ printf ("\n %lf", (*(double*)(lista->dato)));
  22. glist_recorrer (lista, imprimir_entero);
  23. glist_destruir (lista);
  24. return 0;
  25. }
  26.  

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

Código
  1. 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


Conectado Conectado

Mensajes: 924



Ver Perfil
Re: Listas generales en C
« Respuesta #1 en: 21 Abril 2017, 11:08 »

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

while(is_alive(yourself)) {
    make_true(yourself, yourdreams);
}
Fedex15

Desconectado Desconectado

Mensajes: 7


Ver Perfil
Re: Listas generales en C
« Respuesta #2 en: 21 Abril 2017, 15:00 »

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:

Código
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <stddef.h>
  4.  
  5. typedef struct _GNodo {
  6. void *dato;
  7. struct _GNodo *sig;
  8. } GNodo;
  9.  
  10. typedef GNodo* GList;
  11.  
  12. typedef void (*FuncionVisitante) (void* dato);
  13.  
  14. GList glist_crear() {
  15. return NULL;
  16. }
  17.  
  18. void glist_destruir(GList lista) {
  19. GList nodoAEliminar;
  20. while (lista != NULL) {
  21. nodoAEliminar = lista;
  22. lista = lista->sig;
  23. free (nodoAEliminar);
  24. }
  25. }
  26.  
  27. GList glist_agregar_inicio(GList lista, void* dato) {
  28. GList nuevoNodo = malloc (sizeof (GNodo));
  29. nuevoNodo->dato = dato;
  30. nuevoNodo->sig = lista;
  31. return nuevoNodo;
  32. }
  33.  
  34. GList glist_agregar_final (GList lista, void* dato) {
  35. GList nuevoNodo = malloc (sizeof (GNodo));
  36. nuevoNodo->dato = dato;
  37. nuevoNodo->sig = NULL;
  38. if (lista == NULL) {
  39. return nuevoNodo;
  40. }
  41. GList nodo = lista;
  42. for (; nodo->sig != NULL; nodo = nodo->sig);
  43. nodo->sig = nuevoNodo;
  44. return lista;
  45. }
  46.  
  47. void glist_recorrer (GList lista, FuncionVisitante visit) {
  48. for (GList nodo = lista; nodo != NULL; nodo=nodo->sig){
  49. visit (nodo->dato);
  50. }
  51. }
  52.  
  53. static void imprimir_entero(void* dato) {
  54.  printf("%d ", (*(int*)dato));
  55. }
  56. // Lo que yo quiero hacer es algo asi, pero no se como hacerlo:
  57. // Si es entero:
  58. // printf ("%d ", (*(int*)dato));
  59. // Si es double:
  60. //  printf ("%lf ", (*(double*)dato));
  61. // Si es cadena:
  62. //  printf ("%s ", (*(char*)dato));
  63.  
  64. // Como tendria que hacer para saber de alguna forma cual es el tipo
  65. // que esta apuntando el puntero.
  66.  
  67. int main(){
  68. int a = 3;
  69. char c = 'a';
  70. double d = 2.3;
  71. GList lista = glist_crear();
  72. lista = glist_agregar_inicio (lista, &a);
  73. lista = glist_agregar_inicio (lista, &c);
  74. lista = glist_agregar_inicio (lista, &d);
  75. lista = glist_agregar_final (lista, &a);
  76. printf ("%lf %c %d\n", (*(double*)lista->dato),(*(char*)lista->sig->dato),(*(int*)lista->sig->sig->sig->dato) );
  77. glist_recorrer (lista, imprimir_entero);
  78. glist_destruir (lista);
  79. return 0;
  80. }
  81.  

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.

Código
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <stddef.h>
  4.  
  5. #define ENTERO 0
  6. #define DOUBLE 1
  7. #define CADENA 2
  8.  
  9. typedef struct _variante{
  10. int tipo;
  11. void* valor;
  12. } variante;
  13.  
  14. typedef variante* dato;
  15.  
  16. typedef struct _GNodo {
  17. void *dato;
  18. struct _GNodo *sig;
  19. } GNodo;
  20.  
  21. typedef GNodo* GList;
  22.  
  23. typedef void (*FuncionVisitante) (dato d);
  24.  
  25. dato dato_crear (){
  26. dato nuevoDato = (variante*) malloc (sizeof(variante));
  27. return nuevoDato;
  28. }
  29.  
  30. void dato_insertar (dato datos, int tipo, void* d){
  31. datos->tipo = tipo;
  32. datos->valor = d;
  33. }
  34.  
  35.  
  36. void glist_destruir(GList lista) {
  37. GList nodoAEliminar;
  38. while (lista != NULL) {
  39. nodoAEliminar = lista;
  40. lista = lista->sig;
  41. free (nodoAEliminar);
  42. }
  43. }
  44.  
  45. GList glist_crear() {
  46. return NULL;
  47. }
  48.  
  49. GList glist_agregar_inicio(GList lista, void* dato) {
  50. GList nuevoNodo = malloc (sizeof (GNodo));
  51. nuevoNodo->dato = dato;
  52. nuevoNodo->sig = lista;
  53. return nuevoNodo;
  54. }
  55.  
  56. GList glist_agregar_final (GList lista, void* dato) {
  57. GList nuevoNodo = malloc (sizeof (GNodo));
  58. nuevoNodo->dato = dato;
  59. nuevoNodo->sig = NULL;
  60. if (lista == NULL) {
  61. return nuevoNodo;
  62. }
  63. GList nodo = lista;
  64. for (; nodo->sig != NULL; nodo = nodo->sig);
  65. nodo->sig = nuevoNodo;
  66. return lista;
  67. }
  68.  
  69. void glist_recorrer (GList lista, FuncionVisitante visit) {
  70. for (GList nodo = lista; nodo != NULL; nodo=nodo->sig){
  71. visit (nodo->dato);
  72. }
  73. }
  74.  
  75. static void imprimir_entero(dato d) {  
  76.  switch (d->tipo){
  77. case (0):
  78. printf ("%d ", *(int*)d->valor);
  79. break;
  80. case (1):
  81. printf ("%lf ", *(double*)d->valor);
  82. break;
  83. case (2):
  84. printf ("%s ", (char*)d->valor);
  85. break;
  86. }
  87. }
  88. // Lo que yo quiero hacer es algo asi, pero no se como hacerlo:
  89. // Si es entero:
  90. // printf ("%d ", (*(int*)dato));
  91. // Si es double:
  92. //  printf ("%lf ", (*(double*)dato));
  93. // Si es cadena:
  94. //  printf ("%s ", (*(char*)dato));
  95.  
  96. // Como tendria que hacer para saber de alguna forma cual es el tipo
  97. // que esta apuntando el puntero.
  98.  
  99. int main(){
  100. int b = 3;
  101. double num = 6.7;
  102. char cadena[50] = "mundo ";
  103. dato general = dato_crear();
  104. dato general2 = dato_crear();
  105. dato general3 = dato_crear();
  106. dato_insertar(general, ENTERO, &b);
  107. dato_insertar(general2, DOUBLE, &num);
  108. dato_insertar(general3, CADENA, cadena);
  109. GList lista = glist_crear();
  110. lista = glist_agregar_inicio (lista, general);
  111. lista = glist_agregar_inicio (lista, general2);
  112. lista = glist_agregar_inicio (lista, general3);
  113. //~ lista = glist_agregar_final (lista, &a);
  114. glist_recorrer (lista, imprimir_entero);
  115. glist_destruir (lista);
  116. return 0;
  117. }
  118.  
« Última modificación: 21 Abril 2017, 15:44 por Fedex15 » En línea

MAFUS


Conectado Conectado

Mensajes: 924



Ver Perfil
Re: Listas generales en C
« Respuesta #3 en: 21 Abril 2017, 19:30 »

No puedes, C no proporciona reflexión.

Pero gcc sí proporciona, gracias a una extensión del compilador, un operador typeof que sirve para obtener el tipo de un dato. https://gcc.gnu.org/onlinedocs/gcc/Typeof.html

Por otra parte el estándar C11 tiene funciones genéricas las cuales se configuran mediante una macro especial. http://blog.smartbear.com/codereviewer/c11-a-new-c-standard-aiming-at-safer-programming/



Una forma de hacerlo es como la que estás realizando, marcar qué tipo de dato va a guardar la variable dato. Es decir, hacerlo a mano.
« Última modificación: 21 Abril 2017, 19:41 por MAFUS » En línea

while(is_alive(yourself)) {
    make_true(yourself, yourdreams);
}
CalgaryCorpus

Desconectado Desconectado

Mensajes: 62


Ver Perfil
Re: Listas generales en C
« Respuesta #4 en: 24 Abril 2017, 01:41 »

Cuando estas insertando, en estos momentos, con el codigo que presentas, indicas explicitamente el tipo de dato que esta siendo guardado., por ejemplo:

Código:
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.

Código:
typedef struct _variante{
int tipo;
void* valor;
        void (*f)(void *);
       
} variante;
definir las funciones que saben imprimir, por ejemplo:

Código:
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

Código:
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.

Código:
dato_insertar(general, &b, tipo_entero );
   
y finalmente cuando quieras imprimir el dato, solo haces

Código:
dato.f(dato.valor);

y esto imprimira de acuerdo a la funcion que usaste.

Suerte!
En línea

Visita mi perfil en LinkedIn: http://goo.gl/SAaM48
Fedex15

Desconectado Desconectado

Mensajes: 7


Ver Perfil
Re: Listas generales en C
« Respuesta #5 en: 24 Abril 2017, 02:59 »

Cuando estas insertando, en estos momentos, con el codigo que presentas, indicas explicitamente el tipo de dato que esta siendo guardado., por ejemplo:

Código:
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.

Código:
typedef struct _variante{
int tipo;
void* valor;
        void (*f)(void *);
       
} variante;
definir las funciones que saben imprimir, por ejemplo:

Código:
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

Código:
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.

Código:
dato_insertar(general, &b, tipo_entero );
   
y finalmente cuando quieras imprimir el dato, solo haces

Código:
dato.f(dato.valor);

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

Desconectado Desconectado

Mensajes: 62


Ver Perfil
Re: Listas generales en C
« Respuesta #6 en: 24 Abril 2017, 03:04 »

La firma de la funcion modificada que propuse esta mala, o incompleta.

Dice

Código:
void dato_insertar (dato datos, int tipo, void* d, void (*f)() ){

deberia decir

Código:
void dato_insertar (dato datos, void* d, void (*f)(void *) ){
En línea

Visita mi perfil en LinkedIn: http://goo.gl/SAaM48
Páginas: [1] Ir Arriba Respuesta Imprimir 

Ir a:  

Mensajes similares
Asunto Iniciado por Respuestas Vistas Último mensaje
Dudas generales ???
Hacking Avanzado
Anemi 1 1,198 Último mensaje 17 Febrero 2005, 05:21
por Ner0n
Soldaditos y generales.
Diseño Gráfico
APOKLIPTICO 1 541 Último mensaje 30 Marzo 2006, 14:08
por ranslsad
A preguntas generales, respuestas generales
Windows
silverhack 0 4,043 Último mensaje 3 Mayo 2006, 12:38
por silverhack
Uso de Listas: Subprograma que lea 2 listas y forme una.
Dudas Generales
hbenitez 2 1,564 Último mensaje 8 Agosto 2010, 20:11
por hbenitez
Ayuda Acerca De Listas y Listas Circulares (Revienta Memoria :S)
Programación C/C++
Gerik 0 1,289 Último mensaje 12 Septiembre 2010, 01:49
por Gerik
Aviso Legal - Powered by SMF 1.1.21 | SMF © 2006-2008, Simple Machines