Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: NOB2014 en 11 Abril 2017, 18:41 pm



Título: Plantilla para trabajar con archivos en lenguaje C.
Publicado por: NOB2014 en 11 Abril 2017, 18:41 pm
Hola, gente ¿cómo están?
Lo que me trae en este caso no es para pedir ayuda porque el programa no funciona, lo que quisiera es que me digan que debería cambiar, que les parece, ¿está bien encarado?, estoy consiente que esto se lo debería preguntar a un profe o a un amigo, pero como ya algunos conocen por mi edad (65) no tengo ni una cosa ni la otra,-
Es todo, espero que alguien con mucho tiempo lo revice, no tengo ningún apuro. -   

Código
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4.  
  5. #define MAX 80
  6.  
  7. void copiaDeSeguridad( FILE *ptrGuiaTel, FILE *ptrGtTemp ); //GT0001
  8. void ingresarFrase( char frase[] ); //GT0002
  9. void copiar( FILE *ptrGuiaTel, FILE *ptrGtTemp, char frase[] ); //GT0003
  10. void errorEscritura( FILE *ptrGuiaTel, FILE *ptrGtTemp ); //GT0004
  11. void mensaje( void );
  12.  
  13.  
  14. int main( int argc,char **argv ){
  15. FILE *ptrGuiaTel = NULL, *ptrGtTemp = NULL;
  16. char frase[MAX];
  17.  
  18. copiaDeSeguridad( ptrGuiaTel, ptrGtTemp ); //GT0001
  19. ingresarFrase( frase ); //GT0002
  20. copiar( ptrGuiaTel, ptrGtTemp, frase ); //GT0003
  21.  
  22. return EXIT_SUCCESS;
  23. }
  24.  
  25.  
  26. void copiaDeSeguridad( FILE *ptrGuiaTel, FILE *ptrGtTemp ){ //GT0001
  27. char c, x;
  28.  
  29. if( !( ptrGuiaTel = fopen( "archGuiaTel.txt", "r" ))){
  30. mensaje();
  31. exit(1);
  32. }
  33. if( !( ptrGtTemp = fopen( "archGtTemp.txt", "w" ))){
  34. mensaje();
  35. exit(1);
  36. }
  37.  
  38. c = fgetc( ptrGuiaTel );
  39. while ( c != EOF ){
  40. x = fputc( c, ptrGtTemp );
  41. if (x != c){
  42. mensaje();
  43. exit(1);
  44. }
  45. c = fgetc( ptrGuiaTel );
  46. }
  47.  
  48. if( ( fclose( ptrGuiaTel ) ) ){
  49. mensaje();
  50. exit(1);
  51. }
  52. if( ( fclose( ptrGtTemp ) ) ){
  53. mensaje();
  54. exit(1);
  55. }
  56. }
  57.  
  58. void ingresarFrase( char frase[] ){ //GT0002
  59. int ok=0;
  60.  
  61. do{
  62. printf( "\n Ingrese frase.....:" );
  63. fgets( frase, MAX, stdin );
  64. ok = strlen( frase );
  65. }while( ok <= 1 );
  66. }
  67.  
  68. void copiar( FILE *ptrGuiaTel, FILE *ptrGtTemp, char frase[] ){ //GT0003
  69.  
  70. if( !(ptrGuiaTel = fopen( "archGuiaTel.txt", "a" ))){
  71. mensaje();
  72. exit(1);
  73. }
  74.  
  75. fprintf( ptrGuiaTel, "%s", frase );
  76.  
  77. if( fflush( ptrGuiaTel ) != 0){
  78. mensaje();
  79. fclose( ptrGuiaTel );
  80. errorEscritura( ptrGuiaTel, ptrGtTemp ); //GT0004
  81. exit(1);
  82. }
  83.  
  84. if( ( fclose( ptrGuiaTel ) ) ){
  85. mensaje();
  86. exit(1);
  87. }
  88. }
  89.  
  90. void errorEscritura( FILE *ptrGuiaTel, FILE *ptrGtTemp ){ //GT0004
  91.  
  92. if( rename("archGtTemp.txt","archGuiaTel.txt") !=0 ){
  93. mensaje();
  94. exit(1);
  95. }
  96.  
  97. if(remove( "archGuiaTel.txt") !=0 ){
  98. mensaje();
  99. exit(1);
  100. }
  101. }
  102.  
  103. void mensaje( void ){
  104. int ch, a;
  105.  
  106. printf( "\n Ha ocurrido un error y el programa finaliza sin cambios en el archivo." );
  107. printf( "\n Pulse una tecla para continuar..."); a = getchar();
  108. if( a != '\n') while ((ch = getchar()) != EOF && ch != '\n');
  109. }
  110.  
  111. /*
  112. GT0001 - Funcion copiaDeSeguridad
  113. Efectuo una copia del archivo original por si fallara la escritura en el mismo, si esto
  114. ocurriera renombro la copia con el mismo nombre que el archivo original y a este lo borro,
  115. con esto me aseguro que el archivo en disco no quede corrupto. -
  116. Si fallara la apertura de los archivos archGuiaTel.txt o archGtTemp.txt imprimo un mensaje
  117. y cierro el programa (mensaje y exit(1)), lo mismo ocurrira si falla la escritura en el archivo temporal (if (x != c){).-
  118. Si la apertura de los 2 archivos es correcta como asi la escritura, solo queda constatar si
  119. el cierre de los mismos ocurre sin errores, de lo contrario se procedera de la misma manera que en la apertura de los mismos (mensaje y exit (1). -
  120. Nota: En esta funcion se abre y se cierra el archivo "archGtTemp.txt".
  121. //GT0002 - Funcion ingresarFrase  
  122. El do-while es para que no se pueda salir de la funcion si no se ha ingresado por lo menos
  123. un dígito.-
  124. //GT0003 - Funcion copiar
  125. Con fprintf( ptrGuiaTel, "%s", frase ); copio la frase en el buffer intermedio y con fflush
  126. copio la frase desde el buffer al disco rigido(archGuiaTel.txt).-
  127. Verifico si la apertura y cierre del archivo ocurre sin errores.-
  128. En el caso de que fallara fflush llamo a la (//GT0004) funcion errorEscritura para renombrar el archivo archGtTemp.txt por archGuiaTel.txt para luego borrar el
  129.                 archivo original que seguramente si no se pudo escribir es porque está corrupto(al final con remove lo borro). -
  130. */

Saludos.


Título: Re: Plantilla para trabajar con archivos en lenguaje C.
Publicado por: MAFUS en 11 Abril 2017, 19:58 pm
No lo he probado pero estilísticamente está mal.

Usas los argumentos de las funciones como una forma de declarar variables locales. Los argumentos solo deberían usarse para que las funciones se comunicasen datos entre llamadas.

Cuando usas argumentos el compilador genera espacio en la pila para alojar dicho dato y después copia el dato que se va a pasar en esa nueva localidad.

He visto que llevas usando esta técnica desde hace tiempo, pero deberías cambiarla lo más pronto posible: declarar variables locales dentro del cuerpo de las funciones y usar los argumentos únicamente para pasar datos.


Título: Re: Plantilla para trabajar con archivos en lenguaje C.
Publicado por: NOB2014 en 12 Abril 2017, 02:29 am
Hola.
No logro que me caiga la ficha del todo con lo que propones, te pediría tan solo unos minutos para que me hagas una pequeña función diciéndome lo que hago mal y como seria la forma correcta de hacerlo. -

Gracias MAFUS.
Un gran saludo.


Título: Re: Plantilla para trabajar con archivos en lenguaje C.
Publicado por: MAFUS en 15 Abril 2017, 23:57 pm
Así es tu código corregido:

Código
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4.  
  5. #define MAX 80
  6.  
  7. void copiaDeSeguridad( void );
  8. void ingresarFrase( char frase[] );
  9. void copiar( char frase[] );
  10. void errorEscritura( void );
  11. void mensaje( void );
  12.  
  13. int main( void ){
  14. char frase[MAX];
  15.  
  16. copiaDeSeguridad( );
  17. ingresarFrase( frase );
  18. copiar( frase );
  19.  
  20. return EXIT_SUCCESS;
  21. }
  22.  
  23.  
  24. void copiaDeSeguridad( void ){
  25.    FILE *ptrGuiaTel;
  26.    FILE *ptrGtTemp;
  27. char c, x;
  28.  
  29. if( !( ptrGuiaTel = fopen( "archGuiaTel.txt", "r" ))){
  30. mensaje();
  31. exit(1);
  32. }
  33. if( !( ptrGtTemp = fopen( "archGtTemp.txt", "w" ))){
  34. mensaje();
  35. exit(1);
  36. }
  37.  
  38. c = fgetc( ptrGuiaTel );
  39. while ( c != EOF ){
  40. x = fputc( c, ptrGtTemp );
  41. if (x != c){
  42. mensaje();
  43. exit(1);
  44. }
  45. c = fgetc( ptrGuiaTel );
  46. }
  47.  
  48. if( ( fclose( ptrGuiaTel ) ) ){
  49. mensaje();
  50. exit(1);
  51. }
  52. if( ( fclose( ptrGtTemp ) ) ){
  53. mensaje();
  54. exit(1);
  55. }
  56. }
  57.  
  58. void ingresarFrase( char frase[] ){
  59. int ok=0;
  60.  
  61. do{
  62. printf( "\n Ingrese frase.....:" );
  63. fgets( frase, MAX, stdin );
  64. ok = strlen( frase );
  65. }while( ok <= 1 );
  66. }
  67.  
  68. void copiar( char frase[] ){
  69.    FILE *ptrGuiaTel;
  70.  
  71. if( !(ptrGuiaTel = fopen( "archGuiaTel.txt", "a" ))){
  72. mensaje();
  73. exit(1);
  74. }
  75.  
  76. fprintf( ptrGuiaTel, "%s", frase );
  77.  
  78. if( fflush( ptrGuiaTel ) != 0){
  79. mensaje();
  80. fclose( ptrGuiaTel );
  81. errorEscritura( );
  82. exit(1);
  83. }
  84.  
  85. if( ( fclose( ptrGuiaTel ) ) ){
  86. mensaje();
  87. exit(1);
  88. }
  89. }
  90.  
  91. void errorEscritura( void ){
  92.  
  93. if( rename("archGtTemp.txt","archGuiaTel.txt") !=0 ){
  94. mensaje();
  95. exit(1);
  96. }
  97.  
  98. if(remove( "archGuiaTel.txt") !=0 ){
  99. mensaje();
  100. exit(1);
  101. }
  102. }
  103.  
  104. void mensaje( void ){
  105. int ch, a;
  106.  
  107. printf( "\n Ha ocurrido un error y el programa finaliza sin cambios en el archivo." );
  108. printf( "\n Pulse una tecla para continuar..."); a = getchar();
  109. if( a != '\n') while ((ch = getchar()) != EOF && ch != '\n');
  110. }


Título: Re: Plantilla para trabajar con archivos en lenguaje C.
Publicado por: NOB2014 en 26 Abril 2017, 03:30 am
Hola, ¿cómo están?
Gracias MAFUS por el código y gracias por el consejo, estaba cometiendo un error de primer grado, lo voy a tener muy en cuenta de aquí en más. --
La ayudita que les pido ahora es la siguiente, alguien me podría decir como hacer para que falle fflush,
(línea 43) para saber el comportamiento total del programa necesito que esto ocurra, intente abrir el archivo archGuiaTel.txt (línea 36) para lectura pero no me ocasiona un error, simplemente no escribe la frase, pero el programa termina normalmente. -   
Es todo y espero puedan darme la respuesta. -

Código
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4.  
  5. #define MAX 80
  6.  
  7. void ingresarFrase( char frase[] );
  8. void copiar( char frase[] );
  9. void errorEscritura( void );
  10. void copiaDeSeguridad( const char *GtTxt, const char *GtBak );
  11. void mensaje( void );
  12.  
  13. int main( void ){
  14. char frase[MAX];
  15.  
  16. ingresarFrase( frase );
  17. copiar( frase );
  18. copiaDeSeguridad( "archGuiaTel.txt","archGuiaTel.bak" );
  19.  
  20. return EXIT_SUCCESS;
  21. }
  22.  
  23. void ingresarFrase( char frase[] ){
  24. int ok=0;
  25.  
  26. do{
  27. printf( "\n Ingrese frase.....:" );
  28. fgets( frase, MAX, stdin );
  29. ok = strlen( frase );
  30. }while( ok <= 1 );
  31. }
  32.  
  33. void copiar( char frase[] ){
  34. FILE *ptrGtTxt;
  35.  
  36. if( !(ptrGtTxt = fopen( "archGuiaTel.txt", "a" ))){
  37. mensaje();
  38. exit(1);
  39.    }
  40.  
  41. fprintf( ptrGtTxt, "%s", frase );
  42.  
  43. if( fflush( ptrGtTxt ) != 0){
  44. mensaje();
  45. fclose( ptrGtTxt );
  46. errorEscritura( );
  47. exit(1);
  48. }
  49.  
  50. if( ( fclose( ptrGtTxt ) ) ){
  51. mensaje();
  52. exit(1);
  53. }
  54. }
  55.  
  56. void errorEscritura( void ){
  57. if(remove( "archGuiaTel.txt" ) !=0 ){
  58. mensaje();
  59. exit(1);
  60. }
  61.  
  62. if( rename( "archGuiaTel.bak","archGuiaTel.txt") !=0 ){
  63. mensaje();
  64. exit(1);
  65. }
  66. }
  67.  
  68. void copiaDeSeguridad( const char *GtTxt, const char *GtBak ){
  69. FILE *ptrGtTxt, *ptrGtBak;  
  70. char c, x;
  71.  
  72. if( !( ptrGtTxt = fopen( GtTxt, "a" ))){
  73. mensaje();
  74. exit(1);                                
  75. }
  76. if( !( ptrGtBak = fopen( GtBak, "w" ))){
  77. mensaje();
  78. exit(1);                                
  79. }
  80.  
  81. c = fgetc( ptrGtTxt );
  82. while ( c != EOF ){
  83. x = fputc( c, ptrGtBak );
  84. if (x != c){
  85. mensaje();
  86. exit(1);                                
  87. }
  88. c = fgetc( ptrGtTxt );
  89. }
  90.  
  91. if( ( fclose( ptrGtTxt ) ) ){
  92. mensaje();
  93. exit(1);                                
  94. }
  95. if( ( fclose( ptrGtBak ) ) ){
  96. mensaje();
  97. exit(1);                                
  98. }
  99. }
  100.  
  101. void mensaje( void ){
  102. int ch, a;
  103.  
  104. printf( "\n Ha ocurrido un error y el programa finaliza sin cambios en el archivo." );
  105. printf( "\n Pulse una tecla para continuar..."); a = getchar();
  106.    if( a != '\n') while ((ch = getchar()) != EOF && ch != '\n');
  107. }

saludos.
 


Título: Re: Plantilla para trabajar con archivos en lenguaje C.
Publicado por: kuhi en 28 Abril 2017, 01:47 am
Hola 😊👍🏻, tengo una duda: cuando usáis por ejemplo: void mensaje ( void )
Entiendo que estáis declarando una función tipo void pero no entiendo porqué ponéis void como parámetro... puede ser que estéis definiendo una función sin valor de retorno?
Me podéis explicar por favor??
Muchas gracias ❤️


Enviado desde mi iPhone utilizando Tapatalk


Título: Re: Plantilla para trabajar con archivos en lenguaje C.
Publicado por: MAFUS en 28 Abril 2017, 10:09 am
Eso quiere decir que la función no acepta argumentos y no devuelve ningún dato. Es lo mismo que void mensaje(). Es una cuestión de estilos.


Título: Re: Plantilla para trabajar con archivos en lenguaje C.
Publicado por: kuhi en 28 Abril 2017, 22:14 pm
Eso quiere decir que la función no acepta argumentos y no devuelve ningún dato. Es lo mismo que void mensaje(). Es una cuestión de estilos.
Es más correcto utilizarlo así o es 100% idéntico? Saludos y gracias 😊👍🏻


Enviado desde mi iPhone utilizando Tapatalk


Título: Re: Plantilla para trabajar con archivos en lenguaje C.
Publicado por: NOB2014 en 28 Abril 2017, 22:44 pm
Hola.
Pongo void en las funciones que no reciben parametros porque una vez leí que era una ayuda para el compilador pero por más que busco de donde lo saque, no lo encuentro, desde ese momento, en todas mis prácticas lo hago de esa manera. -
Aprovecho para decirles que encontré la manera para forzar a fflush que de error. -

Saludos.


Título: Re: Plantilla para trabajar con archivos en lenguaje C.
Publicado por: CalgaryCorpus en 29 Abril 2017, 17:43 pm
Un poco de historia.
Los primeros compiladores de C eran bastante rudimentarios y no hacian chequeos, suponiendo que el programador sabia lo que hacia. En particular los parametros de las funciones. Al inicio, el lenguaje C permitia no especificar parametros como en
Código:
int mifuncion()
y luego mas adelante invocar esa funcion asi:

Código:
valor = mifuncion( a, b, c );

y el compilador no reclamaba nada.

Con el tiempo, el lenguaje se estandarizo y le agregaron el que uno pueda especificar los tipos de los parametros, pero aun manteniendo la compatibilidad hacia atras, vale decir, si no especificabas nada, no habia chequeos, pero si especificabas algo, entonces habia chequeos.

En este caso, si ponias
Código:
int mifuncion(void)

entonces el compilador va a reclamar si invocas la funcion con algun parametro, pues al poner el void ahi, le estas pidiendo explicitamente al compilador que chequee, y este no va a permitir la invocacion con mas parametros.

Ahora ya no importa la compatibilidad hacia atras, si no pones parametros en la definicion de la funcion el compilador va a chequear que NO pases ningun parametro, del mismo modo si pones void entre los parentesis.

Resumen
  • mucho antes: no habia chequeo alguno
  • luego: chequeo si especificas void
  • ahora: chequeo siempre


Título: Re: Plantilla para trabajar con archivos en lenguaje C.
Publicado por: NOB2014 en 29 Abril 2017, 18:14 pm
Hola, que tengan un muy buen día. -
Rodrigo, gracias por participar y compartir tus conocimientos, espero que con esto la inquietud de kuhi quede totalmente satisfecha.

saludos.