problema con la corriente de entrada de enjuague C
stream (7)
Actualización: Necesita agregar otro getchar () al final de su ciclo para consumir el ''/ n'' que sigue al SÍ / NO. No creo que esta sea la mejor manera de hacerlo, pero hará que tu código funcione tal como está ahora.
while(another==''y'') {
printf("/nEnter name,age and basic salary : ");
fgets(buf, BUF_SIZE, stdin);
sscanf(buf, "%s %d %f", e.name, &e.age, &e.bs);
fwrite(&e,sizeof(e),1,fp);
printf("Add another record (Y/N)");
another=getchar();
getchar();
}
Sugeriría leer los datos que desea analizar (hasta e incluyendo el ''/ n'') en un búfer y luego analizarlos usando sscanf (). De esta forma, consume la nueva línea y puede realizar otras comprobaciones de cordura en los datos.
No puedo descargar stdin aquí, ¿hay alguna forma de eliminar stdin? En caso negativo, ¿cómo hacer que getchar () tome un carácter como entrada del usuario, en lugar de un "/ n" dejado por scanf en el búfer de entrada? ?
#include "stdio.h" #include "stdlib.h" int main(int argc,char*argv[]) { FILE *fp; char another=''y''; struct emp { char name[40]; int age; float bs; }; struct emp e; if(argc!=2) { printf("please write 1 target file name/n"); } fp=fopen(argv[1],"wb"); if(fp==NULL) { puts("cannot open file"); exit(1); } while(another==''y'') { printf("/nEnter name,age and basic salary"); scanf("%s %d %f",e.name,&e.age,&e.bs); fwrite(&e,sizeof(e),1,fp); printf("Add another record (Y/N)"); fflush(stdin); another=getchar(); } fclose(fp); return 0; }
EDIT: - código actualizado, todavía no funciona correctamente
#include "stdio.h" #include "stdlib.h" int main(int argc,char*argv[]) { FILE *fp; char another=''y''; struct emp { char name[40]; int age; float bs; }; struct emp e; unsigned int const BUF_SIZE = 1024; char buf[BUF_SIZE]; if(argc!=2) { printf("please write 1 target file name/n"); } fp=fopen(argv[1],"wb"); if(fp==NULL) { puts("cannot open file"); exit(1); } while(another==''y'') { printf("/nEnter name,age and basic salary : "); fgets(buf, BUF_SIZE, stdin); sscanf(buf, "%s %d %f", e.name, &e.age, &e.bs); fwrite(&e,sizeof(e),1,fp); printf("Add another record (Y/N)"); another=getchar(); } fclose(fp); return 0; } output for this is :- dev@dev-laptop:~/Documents/c++_prac/google_int_prac$ ./a.out emp.dat Enter name,age and basic salary : deovrat 45 23 Add another record (Y/N)y Enter name,age and basic salary : Add another record (Y/N)y Enter name,age and basic salary : Add another record (Y/N)
No es una buena práctica usar fflush (stdin) ya que tiene un comportamiento indefinido. En general, las funciones como scanf () dejan nuevas líneas en stdin. Entonces, es mejor usar funciones que son "más limpias" que scanf (). Puede reemplazar su scanf () con una combinación de fgets () y sscanf () y puede eliminar fflush (stdin).
Recomendaría el enfoque de fgets()
+ sscanf()
que muchas otras personas han sugerido. También podría usar scanf("%*c");
antes de la llamada a getchar()
. Eso esencialmente comerá un personaje.
Si está haciendo esto en Windows, puede usar winapi para descargar el búfer de entrada antes de su getch ().
#include <windows.h>
hStdin = GetStdHandle(STD_INPUT_HANDLE);
FlushConsoleInputBuffer(hStdin);
-o-
#include <windows.h>
FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE));
Use esto en lugar de getchar ():
char another[BUF_SIZE] = "y";
while( ''y'' == another[0] )
{
printf( "/nEnter name,age and basic salary : " );
fgets( buf, BUF_SIZE, stdin );
sscanf( buf, "%s %d %f", e.name, &e.age, &e.bs );
fwrite( &e, sizeof(e) , 1, fp );
printf( "Add another record (Y/N)" );
fgets( another, BUF_SIZE, stdin );
}
fflush(stdin)
es un comportamiento indefinido. En cambio, haz que scanf
"coma" la nueva línea:
scanf("%s %d %f/n", e.name, &e.age, &e.bs);
Todos los demás hacen una buena scanf
sobre scanf
como una mala elección. En su lugar, debe usar fgets
y sscanf
:
const unsigned int BUF_SIZE = 1024;
char buf[BUF_SIZE];
fgets(buf, BUF_SIZE, stdin);
sscanf(buf, "%s %d %f", e.name, &e.age, &e.bs);
Como ya han señalado otros, no debe escribir una estructura en un archivo. En cambio, intente escribir los datos de forma formateada. De esta forma, su archivo de texto se puede analizar línea por línea buscando el último y penúltimo delimitador, por ejemplo, punto y coma. Tenga en cuenta que ciertos caracteres como
''-''
o''.''
puede ocurrir en el campo float stringified.int write_data(FILE *fh, struct emp *e) { if(fh == NULL || e == NULL) return -1; fprintf(fh, "%s;%d;%f", e->name, e->age, e->bs); return 0; }
La otra cosa es cómo todo el mundo sigue recomendando la misma familia de funciones scanf, pero nadie verifica si el valor de retorno es igual al número de campos que debe leer. Creo que es una mala idea, que realmente está buscando problemas. Incluso con el método
strtol
/strtod
necesita una comprobación de errores:int parse_int(char *buf, long *result) { if(buf == NULL || result == NULL) return -1; errno = 0; *result = strtoul(buf, NULL, 0); if(errno != 0) { perror("strtoul"); return -1; } return 0; }
los dos ejemplos de código anteriores devuelven silenciosamente lo que está bien si planea llamarlos usando objetos existentes todo el tiempo; no obstante, considere la posibilidad de imprimir un mensaje de error e ilustre en su documentación que las personas deben verificar los valores devueltos al usar sus funciones.