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

 

 


Tema destacado: Sigue las noticias más importantes de seguridad informática en el Twitter! de elhacker.NET


+  Foro de elhacker.net
|-+  Programación
| |-+  Programación C/C++ (Moderadores: Eternal Idol, Littlehorse, K-YreX)
| | |-+  [Ayuda-C] Bucle infinito
0 Usuarios y 1 Visitante están viendo este tema.
Páginas: [1] Ir Abajo Respuesta Imprimir
Autor Tema: [Ayuda-C] Bucle infinito  (Leído 2,821 veces)
Miky Gonzalez

Desconectado Desconectado

Mensajes: 87

http://mikygonzalez.comule.com/blog/


Ver Perfil WWW
[Ayuda-C] Bucle infinito
« en: 10 Octubre 2013, 18:43 pm »

Estaba programando en C un ensamblador para programas de mi máquina virtual (decidí continuar un proyecto). Tengo el siguiente código:

Código
  1. /*! Ejemplo de lector de archivo */
  2.  
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5.  
  6. /*! Declaración de variables locales */
  7. enum {lex_PARI = '(', lex_PARD = ')', lex_LLAI = '{', lex_LLAD = '}'};
  8. unsigned short int pos = 0x00;
  9. unsigned int codigo_volumen;
  10. unsigned char *codigo;
  11. FILE *codigo_archivo;
  12.  
  13. void siguiente_lexema(unsigned char *codigo);
  14.  
  15. void buscar_caracter(char caracter) {
  16. while((caracter != codigo[pos]) && (pos < codigo_volumen)) {
  17. siguiente_lexema(codigo);
  18. pos++;
  19. }
  20. if(pos == codigo_volumen)
  21. printf("Se esperaba '%c'", caracter);
  22. }
  23.  
  24. // modo == 0 (si cadena)
  25. // modo == 1 (si entero)
  26. void identificador(unsigned char *codigo, char modo) {
  27.  
  28. return;
  29. }
  30.  
  31. int saber_letra(char caracter) {
  32. return (((caracter >= 'A') && (caracter <= 'Z')) || ((caracter >= 'a') && (caracter <= 'z')));
  33. }
  34.  
  35. int saber_numero(char caracter) {
  36. return ((caracter >= '0') && (caracter <= '9'));
  37. }
  38.  
  39. void siguiente_lexema(unsigned char *codigo) {
  40. switch(codigo[pos]) {
  41. case lex_PARI:
  42. printf("Encontrado: %c\n", lex_PARI);
  43. buscar_caracter(lex_PARD);
  44. break;
  45. case lex_LLAI:
  46. printf("Encontrado: %c\n", lex_LLAI);
  47. buscar_caracter(lex_LLAD);
  48. break;
  49. default:
  50. if(saber_letra(codigo[pos]))
  51. identificador(codigo, 0);
  52. else if(saber_numero(codigo[pos]))
  53. identificador(codigo, 1);
  54. /*
  55. * TODO: Mostrar error. Ignorar espacios, salto de línea y tabulador
  56. */
  57. else
  58. ;
  59. break;
  60. }
  61.  
  62. return;
  63. }
  64.  
  65. int main(int argc, char **argv) {
  66. if(argc < 2) {
  67. printf("Uso: %s <archivo>\n", argv[0]);
  68. return 0;
  69. }
  70. codigo_archivo = fopen(argv[1], "r");
  71. if(!codigo_archivo) {
  72. printf("[ASM] Error al leer el archivo %s\n", argv[1]);
  73. return 0;
  74. }
  75.  
  76. /* Calcular tamaño (volumen) del código */
  77. fseek(codigo_archivo, 0, SEEK_END);
  78. codigo_volumen = ftell(codigo_archivo);
  79. rewind(codigo_archivo);
  80. if(!codigo_volumen) {
  81. printf("[ASM] No hay instrucciones...\n");
  82. fclose(codigo_archivo);
  83. return 0;
  84. }
  85.  
  86. /* Reservar el espacio necesario para almacenar
  87. * el código en memoria. Si existe, copiarlo. */
  88. codigo = (unsigned char *)malloc(codigo_volumen);
  89. if(!fread(codigo, 1, codigo_volumen, codigo_archivo)) {
  90. printf("[ASM] Error en lectura de archivo...\n");
  91. fclose(codigo_archivo);
  92. return 0;
  93. } else fclose(codigo_archivo);
  94.  
  95. while(pos < codigo_volumen) {
  96. siguiente_lexema(codigo);
  97. pos++;
  98. }
  99.  
  100. return 0;
  101. }
  102.  

El problema está en que dado un archivo:

Código
  1. {
  2. {
  3. {
  4. ( {} )( } } }
  5.  

Entra en un bucle infinito. He revisado muchas veces el código pero no veo ningún error de direcciones, punteros... ¿Alguien puede determinar a causa de que?


En línea

Mi blog personal, con información acerca de programación, seguridad, desarrollo y electrónica:


EN CONSTRUCCIÓN
0xDani


Desconectado Desconectado

Mensajes: 1.077



Ver Perfil
Re: [Ayuda-C] Bucle infinito
« Respuesta #1 en: 10 Octubre 2013, 21:32 pm »

Quizá sea porque siguiente_lexema() llama a buscar_caracter(), que a su vez llama a siguiente_lexema()...

Si quieres hacer un ensamblador te recomendaría usar un lenguaje más sencillo como Python y expresiones regulares, si el rendimiento no te importa demasiado.


En línea

I keep searching for something that I never seem to find, but maybe I won't, because I left it all behind!

I code for $$$
Hago trabajos en C/C++
Contactar por PM
xv0


Desconectado Desconectado

Mensajes: 1.026



Ver Perfil
Re: [Ayuda-C] Bucle infinito
« Respuesta #2 en: 10 Octubre 2013, 21:56 pm »

Depuralo asi sabras donde esta el problema.

Tambien podrias hacer funciones como esta te dejo este link, es un deliminador de caracteres pero puedes adaptarlo, mira el ultimo mensaje que deje.

Código:
http://foro.elhacker.net/asm/ayuda_con_funcion_split-t386501.15.html

Un saludo.
« Última modificación: 10 Octubre 2013, 21:57 pm por cpu2 » En línea

rir3760


Desconectado Desconectado

Mensajes: 1.639


Ver Perfil
Re: [Ayuda-C] Bucle infinito
« Respuesta #3 en: 11 Octubre 2013, 04:02 am »

El error principal ya lo indico 0xDani:
Quizá sea porque siguiente_lexema() llama a buscar_caracter(), que a su vez llama a siguiente_lexema()...
Y como en ningún momento se modifica el valor de la variable "global" "pos" ello resulta en una recursion infinita.

----

Aparte de eso se puede mejorar el programa:

* Falta consistencia, por ejemplo la función "buscar_caracter" accede directamente a la variable "global" "codigo" mientras que la función "siguiente_lexema" accede a la misma variable en base a su único parámetro.

* Deberías sustituir tus funciones "saber_letra" y "saber_numero" por "isalpha" e "isdigit" (prototipos en <ctype.h>). Si por alguna razón debes utilizar funciones propias puedes eliminar todos los paréntesis en ellas ya que no son necesarios.

* No generes tus propios mensajes de error si una función de entrada/salida falla, en su lugar relega ese trabajo a la función perror.

* Si abres un archivo en modo texto calcular su numero de caracteres en base a fseek+ftell es problemático en el mejor de los casos ya que al hacerlo obtienes la posición en bytes y esto puede funcionar o no.

Un ejemplo, si tenemos en MS Windows el archivo de texto:
Código:
1234
ABCD
Su contenido son dos lineas de texto, los diez caracteres requieren doce bytes (aquí el avance de linea se representa por la secuencia '\r' + '\n').

Si en ese SO ejecutamos el programa:
Código
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3.  
  4. #define NOM_ENTRADA  "Entrada.txt"
  5.  
  6. int main(void)
  7. {
  8.   FILE *entrada;
  9.   long num_bytes;
  10.   int num_chars;
  11.  
  12.   if ((entrada = fopen(NOM_ENTRADA, "rt")) == NULL){
  13.      perror(NOM_ENTRADA);
  14.      return EXIT_FAILURE;
  15.   }
  16.  
  17.   fseek(entrada, 0, SEEK_END);
  18.   num_bytes = ftell(entrada);
  19.  
  20.   rewind(entrada);
  21.   for (num_chars = 0; fgetc(entrada) != EOF; num_chars++)
  22.      ;
  23.   fclose(entrada);
  24.  
  25.   printf("numero de caracteres: %d\n", num_chars);
  26.   printf("numero de bytes: %ld\n", num_bytes);
  27.  
  28.   return EXIT_SUCCESS;
  29. }

Su salida es:
Código:
numero de caracteres: 10
numero de bytes: 12

En Linux no hay problema.

Un saludo
En línea

C retains the basic philosophy that programmers know what they are doing; it only requires that they state their intentions explicitly.
--
Kernighan & Ritchie, The C programming language
Miky Gonzalez

Desconectado Desconectado

Mensajes: 87

http://mikygonzalez.comule.com/blog/


Ver Perfil WWW
Re: [Ayuda-C] Bucle infinito
« Respuesta #4 en: 11 Octubre 2013, 15:51 pm »

Gracias por la ayuda, al final resultó ser un problema estúpido. No aumentaba la variable pos en un determinado caso: que los paréntesis sean escritos juntos.

Respecto al comentario de rir3760:

La falta de consistencia está solucionado. Si te preguntas el porqué paso código como parámetro se debe a que en un futuro implementaré hilos para hacer el proceso más rápido (analizar varios archivos al mismo tiempo). Utilizo funciones (podría hacerlo con un #define pero aumentaría tamaño del código) propias porque me han resultado ser más rápidas (linux).
Los mensajes de error prefiero especificarlos yo, para tener un control absoluto del sistema de errores que se produzcan en el programa.
La forma en la que tengo implementada el código no podría admitir el uso de fgetc() para leer el tamaño del archivo, a no ser que la lectura y el analizado se hagan de una forma atómica. No se producirá ningún error, porque carácteres como ' ', '\t', '\n', '\r'... serán descartados de análisis.

El código resultante:

Código
  1. /*! Ejemplo de lector de archivo */
  2.  
  3. #include <stdio.h>
  4. #include <string.h>
  5. #include <stdlib.h>
  6.  
  7. #define NUM_INSTR 2
  8.  
  9. /*! Declaración de variables locales */
  10. enum {lex_PARI = '(', lex_PARD = ')', lex_LLAI = '{', lex_LLAD = '}'};
  11.  
  12. unsigned short int pos = 0x00;
  13. unsigned int codigo_volumen;
  14. char lista_instrucciones[NUM_INSTR][10] = {
  15. {"PRINT"},
  16. {"EXIT"}
  17. };
  18.  
  19. void siguiente_lexema(unsigned char *codigo);
  20. int saber_letra(char caracter);
  21.  
  22. void buscar_caracter(char caracter, unsigned char *codigo) {
  23. pos++;
  24. while((codigo[pos] != caracter) && (pos < codigo_volumen))
  25. siguiente_lexema(codigo);
  26.  
  27. if(pos == codigo_volumen)
  28. printf("Se esperaba '%c'", caracter);
  29. }
  30.  
  31. /*
  32.  * TODO: Identificar palabra reservada ó símbolo
  33. */
  34. // modo == 0 (si cadena)
  35. // modo == 1 (si entero)
  36. void identificador_cadena(unsigned char *codigo) {
  37. unsigned short int pos_buffer = 0;
  38. char *buffer = (char *)malloc(1 * sizeof(char));
  39.  
  40. while(saber_letra(codigo[pos])) {
  41. buffer[pos_buffer] = codigo[pos];
  42. pos++;
  43. pos_buffer++;
  44. buffer = (char *)realloc(buffer, (pos_buffer + 1) * sizeof(char));
  45. }
  46.  
  47. // Reutilizar variable pos_buffer
  48. for(pos_buffer = 0; pos_buffer < NUM_INSTR; pos_buffer++)
  49. if(strcmp(buffer, lista_instrucciones[pos_buffer]))
  50. printf("Encontrado %s en %s", lista_instrucciones[pos_buffer], buffer);
  51.  
  52. free(buffer);
  53. return;
  54. }
  55.  
  56. int saber_letra(char caracter) {
  57. return ((caracter >= 'A') && (caracter <= 'Z')) || ((caracter >= 'a') && (caracter <= 'z'));
  58. }
  59.  
  60. int saber_numero(char caracter) {
  61. return (caracter >= '0') && (caracter <= '9');
  62. }
  63.  
  64. void siguiente_lexema(unsigned char *codigo) {
  65. switch(codigo[pos]) {
  66. case lex_PARI:
  67. printf("Encontrado: %c\n", lex_PARI);
  68. buscar_caracter(lex_PARD, codigo);
  69. break;
  70. case lex_LLAI:
  71. printf("Encontrado: %c\n", lex_LLAI);
  72. buscar_caracter(lex_LLAD, codigo);
  73. break;
  74. default:
  75. if(saber_letra(codigo[pos]))
  76. identificador_cadena(codigo);
  77. else if(saber_numero(codigo[pos]))
  78. //identificador(codigo, 1);
  79. ;
  80. /*
  81. * TODO: Mostrar error. Ignorar espacios, salto de línea y tabulador
  82. */
  83. else
  84. ;
  85. break;
  86. }
  87.  
  88. pos++;
  89. return;
  90. }
  91.  
  92. int main(int argc, char **argv) {
  93. if(argc < 2) {
  94. printf("Uso: %s <archivo>\n", argv[0]);
  95. return 0;
  96. }
  97. FILE *codigo_archivo = fopen(argv[1], "r");
  98. if(!codigo_archivo) {
  99. printf("[ASM] Error al leer el archivo %s\n", argv[1]);
  100. return 0;
  101. }
  102.  
  103. /* Calcular tamaño (volumen) del código */
  104. fseek(codigo_archivo, 0, SEEK_END);
  105. codigo_volumen = ftell(codigo_archivo);
  106. rewind(codigo_archivo);
  107. if(!codigo_volumen) {
  108. printf("[ASM] No hay instrucciones...\n");
  109. fclose(codigo_archivo);
  110. return 0;
  111. }
  112.  
  113. /* Reservar el espacio necesario para almacenar
  114. * el código en memoria. Si existe, copiarlo. */
  115. unsigned char *codigo = (unsigned char *)malloc(codigo_volumen);
  116. if(!fread(codigo, 1, codigo_volumen, codigo_archivo)) {
  117. printf("[ASM] Error en lectura de archivo...\n");
  118. fclose(codigo_archivo);
  119. return 0;
  120. } else fclose(codigo_archivo);
  121.  
  122. while(pos < codigo_volumen)
  123. siguiente_lexema(codigo);
  124.  
  125. return 0;
  126. }
  127.  
« Última modificación: 11 Octubre 2013, 16:27 pm por Miky Gonzalez » En línea

Mi blog personal, con información acerca de programación, seguridad, desarrollo y electrónica:


EN CONSTRUCCIÓN
Páginas: [1] Ir Arriba Respuesta Imprimir 

Ir a:  

Mensajes similares
Asunto Iniciado por Respuestas Vistas Último mensaje
Como hacer que un bucle no se infinito cuando ingreso letras en un switch
Programación C/C++
zenemijinterjb 1 1,724 Último mensaje 30 Noviembre 2014, 02:26 am
por rir3760
tengo un bucle infinito conmigo, HELP!
Java
sowi12 7 2,854 Último mensaje 15 Septiembre 2015, 22:17 pm
por 0roch1
Ayuda Phyton bucle infinito
Scripting
SkaTrumpet 1 1,684 Último mensaje 1 Diciembre 2015, 01:06 am
por daryo
Bucle Infinito ayuda.
Programación C/C++
jtrujilloj 1 2,147 Último mensaje 13 Febrero 2018, 09:42 am
por vangodp
error, bucle infinito, alguien que me ayude a evitar el bucle infinito
Programación C/C++
marcos0204 4 2,550 Último mensaje 27 Marzo 2020, 22:44 pm
por fary
WAP2 - Aviso Legal - Powered by SMF 1.1.21 | SMF © 2006-2008, Simple Machines