Autor
|
Tema: problemas con fseeks (Leído 5,259 veces)
|
m@o_614
Desconectado
Mensajes: 389
|
Saludos, tengo problemas con unos fseeks que tengo dentro de un ciclo while que me lee un archivo, pero a la hora de imprimir el archivo no lo hace correctamente este es el codigo: #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX 8 typedef enum {INS,OP,DIR,MAQ,CALCULADO,CALCULAR,TOTAL} tabla; void buscarFinLinea(FILE *hc12); void listaTABOP(); char *Tabla_Operandos(FILE *hc12,int tabla); void ignorarEspacios(FILE *hc12); void quitarSaltosLinea(char *cadena); int main() { listaTABOP(); return 0; } void buscarFinLinea(FILE *hc12) { int car; while((car = fgetc(hc12 ))!= '\n') ; } void quitarSaltosLinea(char *c) { char *ptr; if(((ptr = strchr(c ,'\n'))!= NULL )||((ptr = strchr(c ,'\t'))!= NULL )||((ptr = strchr(c ,' '))!= NULL )) *ptr = '\0'; } void listaTABOP() { int car,i,pos,n; FILE *hc12; COD *ultimo = NULL; char *ins,*op,**dir,**maq,**cal,**x_cal,**sum; if((hc12 = fopen("Tabla_OP.txt","r"))!= NULL ) { while((car = fgetc(hc12 ))!= EOF ) { i = 0; ins = Tabla_Operandos(hc12,INS); ignorarEspacios(hc12); op = Tabla_Operandos(hc12,OP); buscarFinLinea(hc12); if((car = fgetc(hc12 )) != '\t') { n = 0; fseek(hc12 ,pos ,SEEK_SET ); ignorarEspacios(hc12); dir = (char**)malloc(sizeof(char*)); dir[i] = Tabla_Operandos(hc12,DIR); ignorarEspacios(hc12); maq = (char**)malloc(sizeof(char*)); maq[i] = Tabla_Operandos(hc12,MAQ); ignorarEspacios(hc12); cal = (char**)malloc(sizeof(char*)); cal[i] = Tabla_Operandos(hc12,CALCULADO); ignorarEspacios(hc12); x_cal = (char**)malloc(sizeof(char*)); x_cal[i] = Tabla_Operandos(hc12,CALCULAR); ignorarEspacios(hc12); sum = (char**)malloc(sizeof(char*)); sum[i] = Tabla_Operandos(hc12,TOTAL); buscarFinLinea(hc12); } else { n = 1; fseek(hc12 ,pos ,SEEK_SET ); dir = (char**)malloc(MAX *sizeof(char*)); maq = (char**)malloc(MAX *sizeof(char*)); cal = (char**)malloc(MAX *sizeof(char*)); x_cal = (char**)malloc(MAX *sizeof(char*)); sum = (char**)malloc(MAX *sizeof(char*)); do { ignorarEspacios(hc12); dir[i] = Tabla_Operandos(hc12,DIR); ignorarEspacios(hc12); maq[i] = Tabla_Operandos(hc12,MAQ); ignorarEspacios(hc12); cal[i] = Tabla_Operandos(hc12,CALCULADO); ignorarEspacios(hc12); x_cal[i] = Tabla_Operandos(hc12,CALCULAR); ignorarEspacios(hc12); sum[i] = Tabla_Operandos(hc12,TOTAL); buscarFinLinea(hc12); i++; }while((car = fgetc(hc12 )) == '\t'); } } } else printf("No se pudo abrir el archivo"); } void ignorarEspacios(FILE *hc12) { int car; do { }while(car == '\t' || car == ' '); } char *Tabla_Operandos(FILE *hc12,int tabla) { int car,lon = 0,pos; char *c; if((tabla==INS)||(tabla==OP)||(tabla==DIR)||(tabla==MAQ)||(tabla==CALCULADO)||(tabla==CALCULAR)) { do { lon++; }while(car != '\t' && car != EOF); } else { do { lon++; }while(car != '\n' && car != EOF); lon--; } fseek(hc12 ,pos ,SEEK_SET ); c = (char*)calloc((lon +1),sizeof(char)); quitarSaltosLinea(c); return c; }
[ y el archivo es quote]ABA NO INH 1806 2 0 2 ADCA SI IMM 89ii 1 1 2 DIR 99dd 1 1 2 EXT B9hhll 1 2 3 IDX A9xb 1 1 2 IDX1 A9xbff 1 2 3 IDX2 A9xbeeff 1 3 4 [D,IDX] A9xb 1 1 2 [IDX2] A9xbeeff 1 3 4[/quote] el problema es que cuando llega al codop ADCA no me imprime toda la linea solo me imprime []....[ADCA]...[SI]...[IMM]...[89ii]....[1]...[1] esto se arregla si le quito el primer fseek() que aparece en el while() de la funcion listaTABOP, pero si se lo quito ahora los codops siguientes al ADCA los imprime sin la primer letra, se la come,entonces como puedo arreglar este problema gracias
|
|
« Última modificación: 30 Enero 2014, 21:57 pm por m@o_614 »
|
En línea
|
|
|
|
x64core
Desconectado
Mensajes: 1.908
|
¿Has depurado la aplicación?
|
|
|
En línea
|
|
|
|
m@o_614
Desconectado
Mensajes: 389
|
Saludos x64Core el problema es que no se usar el depurador de codeblocks :S lo intente con un tutorial pero no pude
|
|
|
En línea
|
|
|
|
x64core
Desconectado
Mensajes: 1.908
|
Saludos x64Core el problema es que no se usar el depurador de codeblocks :S lo intente con un tutorial pero no pude
Pues te recomiendo que empieces a aprender a usarlo usar los depuradores para encontrar errores en tus programas es tan indispensable y realmente no es nada dificil.
|
|
|
En línea
|
|
|
|
Yoel Alejandro
|
Bueno x64Core particularmente no soy partidario de usar depuradores o cosas por es estilo, prefiero ir "a manita limpia", y me ha funcionado bien porque así ejercitas más el cerebro, jeje El problema al parecer es que te mueves para adelante y para atrás en el archivo, abusando de fseek. Un buen programador debe ser cauto, debe simplemente evitar andar por terrenos peligrosos, y el estilo de tu programación está siendo definitivamente muy vulnerable. Cualquier error o descuido y tienes un comportamiento completamente impredecible. Usa el principio de "divide y vencerás". Ve, hazlo así. Coje una línea del archivo txt, y la pasas a una función que analice sintácticamente para detectar sus divisiones en columnas con el carácter tabulador, es decir, lo que hace tablaOperandos. Pero que tablaOperandos y listaTABOP NO SE MUEVAN juntas por el mismo archivo. Eso NUNCA se hace, cada función debe tener su espacio de trabajo "privado". ¿Entiendes la filosofía subyacente? Entonces, vamos a hacer una función que vaya cogiendo una línea del archivo, y la copie a un arreglo tipo búfer, y se la pase a tablaOperandos, así esta última lee del búfer y no se mete para nada con el archivo original (reduciendo el riesgo de conflictos). En tu código original tenías un problema porque tablaOperandos al leer la línea avanzaba el indicador de posición de archivo, luego tenías que devolverlo a su posición original con [ttfseek[/tt], etc .... muy engorroso. Con esta solución no tienes que hacer nada de eso: #define CR 13 #define LF 10
void readLine ( FILE* hc12, char *buffer ) { cchar c; int i;
i = 0; while ( !feof(hc12) && (c = fgetc(hc12)) != CR && c != LF ) buffer[i++] = c;
buffer[i] = '\0';
/* avanzamos hasta que no haya CR ni LF */ while ( ( c = fgetc(hc12) ) == CR || c == LF ) ; /* devolvemos el último carácter leído */ if ( !feof(hc12) ) ungetc(c, hc12); }
y listo, agarras ese buffer y se lo pasas a tablaOperandos. Claro, antes debes haber definido el buffer como un arreglo con la suficiente longitud para contener cualquier posible línea del archivo (no se, 100 caracteres quizás). Ahora acomoda tablaOperandos para que trabaje sobre un arreglo y no sobre un fichero. Te explico la última parte del código antes mostrado. En ficheros de texto el fin de línea se hace con una sucesión de dos caracteres, generalmente el <i>carriage return</i> CR seguido de <i>linefeed</i> LF. Entonces, si alcanzas digamos el CR, pues cierras el búfer. Pero al invocar el nuevo la función, leerá el LF y cerrará el búfer ... ¡vacío! O sea, que después de una llamada exitosa a readLinea la próxima llamada que ejecutes devolverá un búfer vacío. Para evitar eso, se bede avanzar el indicador de posición de archivo hasta no encontrar ni CR ni LF, luego de cerrar el búfer de línea. Es lo que hace el: /* avanzamos hasta que no haya CR ni LF */ while ( ( c = fgetc(hc12) ) == CR || c == LF ) ; /* devolvemos el último carácter leído */ if ( !feof(hc12) ) ungetc(c, hc12);
Te voy a explicar algo, el uso de ungetc(). Supón que tienes un fichero así: entonces empieza a leer la línea Pedro, hasta que haya la secuencia CR + LF. Primero lee CR, entonces sabe que debe continuar hasta que no haya ni CR ni LF. Así leee CR, luego LF, luego la M inicial de "Maria". Ahí sabe que se terminó la primera línea. Pero hemos agarrado la 'M', luego tenemos que "devolverla" al fichero, por eso usamos ungetc. Es algo parecido a lo que hacías con fseek( hc12, -1, SEEK_CUR ).
|
|
« Última modificación: 5 Febrero 2014, 03:32 am por yoel_alejandro »
|
En línea
|
Saludos, Yoel. P.D..- Para mayores dudas, puedes enviarme un mensaje personal (M.P.)
|
|
|
Yoel Alejandro
|
Continuando con el tema, ahora queremos una función que tome un búfer de línea del archivo, y sepa encontrar los distintos campos separados por espacios. Aquí la tienes, su código es breve pero maneja unos conceptos un poquito complicados de apuntadores, como por ejemplo el apuntador pasado por referencia o puntero-a-puntero del tipo char **. Si no lo entiendes me lo preguntas luego y te lo explico bien.: /* Lee un campo del búfer, considerando un campo como toda sucesión de caracteres de no espacio. Devuelve NULL si no hay más campos que leer */ char * readField( char ** buffer_ptr ) { int i; char c; char * buffer = *buffer_ptr; if ( *buffer == '\0' ) return NULL; /* elimina los espacios iniciales */ while ( *buffer == ' ' || *buffer == '\t' ) buffer++; /* ahora toma la porción inicial de la cadena hasta encontrar espacio o tabulador */ i = 0; while ( (c = buffer[i]) != '\0' && c != ' ' && c != '\t' ) i++; /* finaliza la sub-cadena donde halló el carácter espacio o tabulador */ buffer[i] = '\0'; /* y si hay más sub-cadenas que leer, avanza el búfer */ if ( c != '\0' ) *buffer_ptr = buffer + i + 1; else *buffer_ptr = buffer + i; if ( i > 0 ) return buffer; /* leyó al menos un carácter */ else return NULL; /* no leyó nada */ }
|
|
« Última modificación: 7 Febrero 2014, 02:50 am por yoel_alejandro »
|
En línea
|
Saludos, Yoel. P.D..- Para mayores dudas, puedes enviarme un mensaje personal (M.P.)
|
|
|
Yoel Alejandro
|
Ok, ahora vamos a poner todo junto, a mí me salió en apenas 89 líneas de código. Y creé un fichero de texto de prueba con el mismo contenido que tú dices, y me imprimió la tabla perfecta Es cuestión de ser hábil combinando las cosas, así puedes lograr mucho con poco ... Bueno, espero te sirva, aquí tienes el fuente completo con el main() y todo, sólo de copiar, pegar, compilar y probar. #include <stdlib.h> #include <stdio.h> #define CR 10 #define LF 13 typedef enum {INS, OP, DIR, MAQ, CALCULADO, CALCULAR, TOTAL} tabla; void readLine ( FILE *, char * ); char * readField( char ** ); int main() { char * buffer, * old_buffer; char * field; FILE * hc12; if ( ( buffer = (char *) malloc( 101 * sizeof(char) ) ) == NULL ) return -1; if ( ( field = (char *) malloc( 101 * sizeof(char) ) ) == NULL ) return -1; if ( ( hc12 = fopen( "file1.txt", "r") ) == NULL ) return -1; while ( !feof( hc12) ) { readLine( hc12, buffer); old_buffer = buffer; while ( ( field = readField( &buffer ) ) != NULL ) { printf("%s\t", field); } printf("\n"); buffer = old_buffer; } fclose( hc12 ); return 0; } void readLine ( FILE *hc12, char *buffer ) { char c; int i; i = 0; while ( !feof(hc12) && (c = fgetc(hc12)) != CR && c != LF ) buffer[i++] = c; buffer[i] = '\0'; /* avanzamos hasta que no haya CR ni LF */ while ( ( c = fgetc(hc12) ) == CR || c == LF ) ; /* devolvemos el último carácter leído */ if ( !feof(hc12) ) ungetc(c, hc12); } /* Lee un campo del búfer, considerando un campo como toda sucesión de caracteres de no espacio. Devuelve NULL si no hay más campos que leer */ char * readField( char ** buffer_ptr ) { int i; char c; char * buffer = *buffer_ptr; if ( *buffer == '\0' ) return NULL; /* elimina los espacios iniciales */ while ( *buffer == ' ' || *buffer == '\t' ) buffer++; /* ahora toma la porción inicial de la cadena hasta encontrar espacio o tabulador */ i = 0; while ( (c = buffer[i]) != '\0' && c != ' ' && c != '\t' ) i++; /* finaliza la sub-cadena donde halló el carácter espacio o tabulador */ buffer[i] = '\0'; /* y si hay más sub-cadenas que leer, avanza el búfer */ if ( c != '\0' ) *buffer_ptr = buffer + i + 1; else *buffer_ptr = buffer + i; if ( i > 0 ) return buffer; /* leyó al menos un carácter */ else return NULL; /* no leyó nada */ }
Pruébalo y me dices!! ========================================== Por cierto y aparte, noté que tienes en el código original una sentencia que no entiendo bien: dir = (char**)malloc(sizeof(char*)); dir[i] = Tabla_Operandos(hc12,DIR);
Ok, ve. Con el malloc defines un arreglo dir de UN único elemento del tipo puntero a char, que luego rellenas con el string que produce la función Tabla_Operandos. Ahora, dos preguntas: ¿Dónde reservas el espacio de la memoria para los restantes elementos del arreglo dir, aparte del primero? Además, si dir contendrá un string, ¿dónde reservas la memoria para dicho arreglo de caracteres? Eso tiene que hacerse de la siguiente manera:
/* Reservando el arreglo dir como arreglo de cadenas */ / * (dir_length es la longitud que esperas para dir ) */ dir = (char **) malloc( dir_length * sizeof (char *) ); /* ahora se reserva memoria para cada string dentro del arreglo */ for ( i = 0; i < dir_length; i++ ) dir[i] = (char *) malloc( s_length * sizeof(char) ); /* donde s_length es la longitud deseada para cada string */
De hecho, no se cómo el programa no te produjo un error de "violación de segmento" en tiempo de ejecución ... De, hecho, cada vez que se usa malloc uno tiene que comprobar si la asignación de memoria se produjo con éxito (casi siempre así sucede, pero no se puede dar por sentado). Si no se pudo asignar memoria, se debe salir del programa: /* Reservando el arreglo dir como arreglo de cadenas */ / * (dir_length es la longitud que esperas para dir ) */ dir = (char **) malloc( dir_length * sizeof (char *) ); if ( dir == NULL ) return -1; /* ahora se reserva memoria para cada string dentro del arreglo */ for ( i = 0; i < dir_length; i++ ) { dir[i] = (char *) malloc( s_length * sizeof(char) ); if ( dir[i] == NULL ) return -1; }
y esto te evitará cualquier "comportamiento inesperado" del programa, para que no te pase como a Windows que se cuelga a cada rato jeje. Saludos, y quedo a la orden para cualquier cosa .... Yoel
|
|
« Última modificación: 7 Febrero 2014, 02:51 am por yoel_alejandro »
|
En línea
|
Saludos, Yoel. P.D..- Para mayores dudas, puedes enviarme un mensaje personal (M.P.)
|
|
|
rir3760
Desconectado
Mensajes: 1.639
|
El problema al parecer es que te mueves para adelante y para atrás en el archivo, abusando de fseek. Eso es algo que ya se recomendó a m@o_614 en otros temas pero por alguna razón (valida o no, no lo se) simplemente no la sigue. Te explico la última parte del código antes mostrado. En ficheros de texto el fin de línea se hace con una sucesión de dos caracteres, generalmente el <i>carriage return</i> CR seguido de <i>linefeed</i> LF. Entonces, si alcanzas digamos el CR, pues cierras el búfer. Pero al invocar el nuevo la función, leerá el LF y cerrará el búfer ... ¡vacío! O sea, que después de una llamada exitosa a readLinea la próxima llamada que ejecutes devolverá un búfer vacío. Para evitar eso, se bede avanzar el indicador de posición de archivo hasta no encontrar ni CR ni LF, luego de cerrar el búfer de línea. No es necesario. Cuando se abre un archivo en modo texto (como es nuestro caso) las funciones de la biblioteca estándar convierten el carácter (o caracteres) que indican un avance de linea a '\n' de forma transparente. El proceso opuesto (convertir '\n' a lo que sea indique un avance de linea) también aplica. Esa es una de las razones por las cuales no se recomienda el uso de fseek con streams en modo texto: no se puede garantizar que el numero de bytes coincida con el numero de caracteres. Ya que la aproximación es leer la linea descartando el carácter '\n' la función se puede reducir a: void readLine(FILE *in, char *line) { int ch; while ((ch = fgetc(in )) != EOF && ch != '\n') *line++ = ch; *line = '\0'; }
Se puede mejorar bastante pasando como argumento la capacidad del array y retornando un valor útil (el numero de caracteres almacenados). 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
|
|
|
x64core
Desconectado
Mensajes: 1.908
|
@yoel_alejandro: En proyectos simples es facil, pero en proyectos considerablemente grandes no podes esperar que has manipulado todos los posibles errores. Pero con ese comentario luces de las personas que tiene poca experiencia en eso. de todos modos espero verte más seguido por aquí ya vamos a ver si realmente sabes como dices.
|
|
|
En línea
|
|
|
|
Yoel Alejandro
|
A ver, rir3760, explícame bien lo del problema con el avance de línea, porque según recuerdo una vez tuve problemas con eso. De ahí que siempre le pongo dicha prevención en el código. Tengo entendido además que por lo general los sistemas Windows codifican el fin de línea con dos caracteres (0x0D + 0x0A, o en decimal 13 + 10), mientras los UNIX usan simplemente el 0x0A. Vamos por partes: Me tratas de decir que si por ejemplo fgetc() encuentra una sucesión CR + LF , entonces lee un sólo '\n' y avanza el indicador de posición de archivo en dos bytes, de modo que la próxima llamada a fgect() leerá el siguiente carácter después del LF. ¿¿Es eso así?? ============== Ah, y x64Core, no ingresé a este foro para pelear con nadie, sino para ayudar a los demás. Simplemente tengo una filosofía de que me gusta hacer las cosas a mano, en lugar de recurrir a recursos o softwares sofisticados. Por ejemplo, uso la IDE más sencilla y sólo como editor, pues rara vez compilo usando los íconos de la barra de herramientas. Yo compilo desde la terminal y le meto yo mismo las directivas de "include" y de "lib" en la orden de compilación. Hasta ahora me ha funcionado y he creado aplicaciones de cierta complejidad. Por supuesto me lleva más tiempo pero estoy seguro de que he construido y verificado POR MÍ MISMO cada línea de mi código, por eso confío en él. De nuevo, no es por polemizar, simplemente es mi filosofía de trabajo. Cada quién tiene la suya y se le respeta
|
|
« Última modificación: 7 Febrero 2014, 03:27 am por yoel_alejandro »
|
En línea
|
Saludos, Yoel. P.D..- Para mayores dudas, puedes enviarme un mensaje personal (M.P.)
|
|
|
|
Mensajes similares |
|
Asunto |
Iniciado por |
Respuestas |
Vistas |
Último mensaje |
|
|
problemas con problemas con NVidia FX5700LE
Juegos y Consolas
|
[D4N93R]
|
0
|
2,428
|
12 Abril 2005, 18:31 pm
por [D4N93R]
|
|
|
problemas Nero-problemas Roxio-problemas sonido de PC
Multimedia
|
mohabe
|
1
|
3,577
|
5 Abril 2006, 04:47 am
por fer63
|
|
|
listas enlazadas problemas resueltos todo un paquete de 13 problemas
Java
|
fiisi
|
4
|
55,407
|
9 Junio 2009, 02:25 am
por sapito169
|
|
|
Problemas con html5 amigos... tengo los siguientes problemas...
Desarrollo Web
|
XXXXXX
|
0
|
3,480
|
16 Junio 2010, 19:35 pm
por XXXXXX
|
|
|
problemas que tube con la proteccion de mi equipo. y problemas que tengo ahora
Seguridad
|
boot/expert
|
4
|
5,057
|
20 Septiembre 2012, 20:29 pm
por boot/expert
|
|