File processing in C; won't take input - c

I'm starting to learn file processing in C. The point of this specific program is to make a file called "clients.dat" where I store the account number, name, and balance of clients at a bank, lets say. I've worked and refined the code so that its a perfect replica of what the textbook provides as an example, yet for some reason mine loops endlessly after the first "scanf" and reprints question marks unto oblivion, without ever making it to the scanf statement inside the while loop. Would anyone have any suggestions as to why this is happening? My compiler is Netbeans and I'm running it on Linux-Ubuntu.
#include <stdio.h>
#include <stdlib.h>
/*
*
*/
int main() {
unsigned int actNumber;
char actName[30];
long double actBalance;
FILE *fPtr;
if((fPtr = fopen("clients.dat", "w")) == NULL) {
printf("File could not be found.\n");
}
else {
printf("Enter the Account Number, Name, and Balance.\n Hit the EoF to exit.\n");
printf("%s","?");
scanf("%d%29s%lf", &actNumber, actName, &actBalance);
while (!feof(stdin)) {
fprintf(fPtr, "%d, %29s, %.2lf\n", actNumber, actName, actBalance);
printf("%s", "?");
scanf("%d%29s%lf", &actNumber, actName, &actBalance);
}
fclose(fPtr);
}
return;
}

The end of file marker is set on stdin only when you press a special key combination on the console.
You can make your loop work correctly by using the return value of scanf(), like this
while (scanf("%d%29s%lf", &actNumber, actName, &actBalance) == 3)
{
fprintf(fPtr, "%d, %29s, %.2lf\n", actNumber, actName, actBalance);
printf("%s", "?");
}
After the first scanf() a '\n' character is left in the input stream, when you call scanf() again inside the loop, the character is consumed then ignored, and scanf() fails returning a value that is less than 3, the process is repeated over and over causing the infinite loop.
The following solution, however, is better. Using fgets() allows a better handiling of the '\n' character left unread in the stdin,
char line[100];
while (fgets(line, sizeof(line), stdin) != NULL)
{
if (sscanf(line, "%d%29s%lf", &actNumber, actName, &actBalance) != 3)
continue;
fprintf(fPtr, "%d;%29s;%.2lf\n", actNumber, actName, actBalance);
fprintf(stdout, "?");
}
note that I remove the white spaces in the printf() format, and replaced the , with ; because in some locales the , is the decimal separator, it's just instintictive not to use it, you can use it if you ensure that . is the decimal separator.

Related

fscanf not returning EOF or fscanf going to infinite loop in C

I am trying to write a few lines to a file. After the line are written, when I try to read those lines from file using fscanf it is going into infinite loop. fprintf is working but fscanf is going to an infinite loop.
#include<stdio.h>
#include<stdlib.h>
void main()
{
FILE *fp;
int roll;
char name[25];
float marks;
char ch;
fp = fopen("file.txt","w");
if(fp == NULL)
{
printf("\nCan't open file or file doesn't exist.");
exit(0);
}
do
{
printf("\nEnter Roll : ");
scanf("%d",&roll);
printf("\nEnter Name : ");
scanf("%s",name);
printf("\nEnter Marks : ");
scanf("%f",&marks);
fprintf(fp,"%d%s%f",roll,name,marks);
printf("\nDo you want to add another data (y/n) : ");
ch = getche();
}while(ch=='y' || ch=='Y');
printf("\nData written successfully...");
printf("\nData in file...\n");
while((fscanf(fp,"%d%s%f",&roll,name,&marks))!=EOF)
printf("\n%d\t%s\t%f",roll,name,marks);
fclose(fp);
}
You have opened the file for writing (mode "w"), so your scanf calls are almost certainly failing. Even if you fix the mode, it is not at all surprising that:
while((fscanf(fp,"%d%s%f",&roll,name,&marks))!=EOF)
goes into an infinite loop. If the next character in the stream is not a valid character in an integer, then scanf will return zero and not consume it. It will repeatedly attempt to read that character as an integer and repeatedly fail. The correct approach here is probably to stop using scanf entirely, but a quick work-around may be something like:
int rv;
while( (rv = fscanf(fp,"%d%s%f",&roll,name,&marks)) != EOF ){
if( rv == 3 ){
printf(...);
} else {
/* probably the right thing to do is break out of
the loop and emit an error message, but maybe
you just want to consume one character to progress
in the stream. */
if( fgetc(fp) == EOF ){
break;
}
}
}
it would be more common to write while( 3 == fscanf(...)) and just emit an error message on bad input, but something like the above kludge might be useful (depending on your use case).
But you need to fix the open mode. Probably you just want to close the file after the write loop (you certainly need to flush it before you can expect to read from the file) and re-open in with mode "r".

How can I clear the input buffer without using rewind function? [duplicate]

I am not able to flush stdin here, is there a way to flush it? If not then how to make getchar() to take a character as input from user, instead of a "\n" left by scanf() in the input buffer??
#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: updated code, still not working properly
#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:
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)
fflush(stdin) is undefined behaviour(a). Instead, make scanf "eat" the newline:
scanf("%s %d %f\n", e.name, &e.age, &e.bs);
Everyone else makes a good point about scanf being a bad choice. Instead, you should use fgets and 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);
(a) See, for example, C11 7.21.5.2 The fflush function:
int fflush(FILE *stream) - If stream points to an output stream or an update stream in which the most recent operation was not input, the fflush function causes any unwritten data for that stream to be delivered to the host environment to be written to the file; otherwise, the behavior is undefined.
Update: You need to add another getchar() at the end of your loop to consume the '\n' that follows the Y/N. I don't think this is the best way to go, but it will make your code work as it stands now.
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();
}
I would suggest reading the data you want to parse (up to and including the '\n') into a buffer and then parse it out using sscanf(). This way you consume the newline and you can perform other sanity checks on the data.
Use this instead of 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 );
}
It's not a good practice to use fflush( stdin ) as it has undefined behavior. Generally, functions like scanf() leaves trailing newlines in stdin. So, it is better to use functions that are "cleaner" than scanf(). You can replace your scanf() with a combination of fgets() and sscanf() and you can do away with fflush( stdin ).
I would recommend the fgets()+sscanf() approach that a lot of other people have suggested. You could also use scanf("%*c"); before the call to getchar(). That will essentially eat a character.
If you are doing this under windows, you can use winapi to flush input buffer before your getch().
#include <windows.h>
hStdin = GetStdHandle(STD_INPUT_HANDLE);
FlushConsoleInputBuffer(hStdin);
-or-
#include <windows.h>
FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE));
As others already pointed out, you should not write a struct to a file. Instead, try to write the data in a formatted manner. This way your text file can be parsed line-by-line by finding the last and second-to-last delimiters, for example semicolons. Keep in mind that certain characters like '-' or '.' may occur in the stringified float field.
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;
}
The other thing is how everybody keeps recommending the same scanf family of functions, but nobody ever checks whether the return value is equal to the number of fields to be read. I think that is a bad idea, effectively asking for trouble. Even with the strtol/strtod way you need error checking:
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;
}
the two code examples above return silently which is fine if you plan to call them using existing objects all the time; consider printing an error message, though, and illustrate in your documentation that people should check the return values when using your functions.
stdin is not something flushable, you can flush only output streams. I.e. you don't need to call flush on stdin at all.

Console not waiting for input. (C language)

When I execute my code below. It waits for my input for entering a file name. But it doesn't wait for me to enter a filename, but rather just skips it to the _getch() part of it. I'm unable to add a sentence.
Code not working:
#include <stdio.h>
main() {
FILE *fp;
char fnamer[100] = ""; //Storing File Path/Name of Image to Display
printf("\n\nPlease Enter the Full Path of the Image file you want to view: \n");
scanf("%s", &fnamer);
fp = fopen(fnamer, "w");
if (fp == NULL)
{
printf("\n%s\" File NOT FOUND!", fnamer);
}
char c[1000];
printf("Enter a sentence:\n");
gets(c);
fprintf(fp, "%s", c);
fclose(fp);
_getch();
}
Code that works and waits for entering a sentence:
#include <stdio.h>
#include <stdlib.h> /* For exit() function */
int main()
{
char c[1000];
FILE *fptr;
fptr = fopen("program.txt", "w");
if (fptr == NULL){
printf("Error!");
exit(1);
}
printf("Enter a sentence:\n");
gets(c);
fprintf(fptr, "%s", c);
fclose(fptr);
return 0;
}
Both are so similar right there in the end for the prompt asking for a sentence. It doesn't make sense.
you have to flush your input after using scanf.
put a getchar() after every scanf
You are encountering a very common problem when using stdin to receive input, which is after your first scanf call there is a dangling \n character which gets stuck in the buffer from the enter key. To clear this buffer in a portable easy way, add something like
char c;
while ( (c = getchar()) != '\n' && c != EOF ) { }
This simply initializes a character, and then calls get char as many times as needed until it reaches '\n' or 'EOF', which is immediately in your case.
tl;dr :
Your buffer looks like this
hello.txt\n <-- "comes from the enter key"
and when you try to use get(c) it takes the \n as the next enter key.
The rule is never mix scanf and [f]gets. scanf stops before the next unused character, generaly a blank, and the end of line is composed of blank characters.
You could try to put a dummy fgets between the last scanf and the first real fgets. That will ensure that you are now positionned on a beginning of line before reading. Alternatively, you could read everything in lines with fgets, and parse the lines with sscanf. That is what I prefere as soon as I want my input to be line oriented. And always control return values of input functions, it will avoid a progam suddenly going mad without any indication simply because one input gave an ignored error.
And last and not least: never use gets but only fgets, the former is for decades in the hall of shame as the cause of uncountable buffer overflows
Code could become:
#include <stdio.h>
#include <string.h>
main() {
FILE *fp;
char fnamer[100] = ""; //Storing File Path/Name of Image to Display
char c[1000], *ix;
int cr;
printf("\n\nPlease Enter the Full Path of the Image file you want to view: \n");
cr = scanf("%s", &fnamer);
if (cr != 1) {
// process error or abort with message
}
fp = fopen(fnamer, "w");
if (fp == NULL)
{
printf("\n%s\" File NOT FOUND!", fnamer);
return 1; // do not proceed after a fatal error!
}
for(;;) { // read until a newline in input
ix = fgets(c, sizeof(c), stdin);
if (ix == NULL) {
// end of input: abort
}
if (strcspn(c, "\n") < strlen(c)) break;
}
printf("Enter a sentence:\n");
ix = fgets(c, sizeof(c), stdin);
c[strcspn(c, "\n")] = '\0'; // remove end of line to get same data as gets
fprintf(fp, "%s", c);
fclose(fp);
_getch();
}
main() {
FILE *fp;
char fnamer[100]=""; //Storing File Path/Name of Image to Display
printf("\n\nPlease Enter the Full Path of the Image file you want to view: \n");
fgets ( fnamer,100,stdin); //fgets(name, sizeof(name), stdin);
fp=fopen(fnamer,"w");
if(fp==NULL)
{
printf("\n%s\" File NOT FOUND!",fnamer);
getch();
exit(1);
}
}
I Think best way to do,use fgets insted of scanf,Because
fgets() can read any open file, but scanf() only reads standard input(user given).
fgets() reads a line of text from a file; scanf() can be used for that but also handles conversions
from string to built in numeric types

How to read a integer followed by a string in C? [duplicate]

This question already has an answer here:
How to read / parse input in C? The FAQ
(1 answer)
Closed 6 years ago.
I am trying to write a simple program which will read two input lines, an integer followed by a string. However, it doesn't seem to work for me.
int main()
{
int i;
char str[1024];
scanf("%d", &i);
scanf("%[^\n]", str);
printf("%d\n", i);
printf("%s\n", str);
return 0;
}
Immediately after entering the integer and pressing "Enter", the program prints the integer. It doesn't wait for me to enter the string. Whats wrong? Whats the correct way to program this?
What you need to know
The problem with %[^\n] is that it fails when the first character to be read is the newline character, and pushes it back into the stdin.
The Problem
After you enter a number for the first scanf, you press Enter. %d in the first scanf consumes the number, leaving the newline character ('\n'), generated by the Enter keypress, in the standard input stream (stdin). %[^\n] in the next scanf sees this \n and fails for the reason given in the first paragraph of this answer.
Fixes
Solutions include:
Changing scanf("%d", &i); to scanf("%d%*c", &i);. What %*c does is, it scans and discards a character.
I wouldn't recommend this way because an evil user could trick the scanf by inputting something like <number><a character>\n, ex: 2j\n and you'll face the same problem again.
Adding a space (any whitespace character will do) before %[^\n], i.e, changing scanf("%[^\n]", str); to scanf(" %[^\n]", str); as #Bathsheba mentioned in a comment.
What the whitespace character does is, it scans and discards any number of whitespace characters, including none, until the first non-whitespace character.
This means that any leading whitespace characters will be skipped when inputting for the second scanf.
This is my recommendation: Clear the stdin after every scanf. Create a function:
void flushstdin(void)
{
int c;
while((c = getchar()) != '\n' && c != EOF);
}
and call it after every scanf using flushstdin();.
Other issues:
Issues unrelated to your problem include:
You don't deal with the case if scanf fails. This can be due to a variety of reasons, say, malformed input, like inputting an alphabet for %d.
To do this, check the return value of scanf. It returns the number of items successfully scanned and assigned or -1 if EOF was encountered.
You don't check for buffer overflows. You need to prevent scanning in more than 1023 characters (+1 for the NUL-terminator) into str.
This can be acheived by using a length specifier in scanf.
The standards require main to be declared using either int main(void) or int main(int argc, char* argv[]), not int main().
You forgot to include stdio.h (for printf and scanf)
Fixed, Complete Program
#include <stdio.h>
void flushstdin(void)
{
int c;
while((c = getchar()) != '\n' && c != EOF);
}
int main(void)
{
int i;
char str[1024];
int retVal;
while((retVal = scanf("%d", &i)) != 1)
{
if(retVal == 0)
{
fputs("Invalid input; Try again", stderr);
flushstdin();
}
else
{
fputs("EOF detected; Bailing out!", stderr);
return -1;
}
}
flushstdin();
while((retVal = scanf("%1023[^\n]", str)) != 1)
{
if(retVal == 0)
{
fputs("Empty input; Try again", stderr);
flushstdin();
}
else
{
fputs("EOF detected; Bailing out!", stderr);
return -1;
}
}
flushstdin();
printf("%d\n", i);
printf("%s\n", str);
return 0;
}
This simply, will work:
scanf("%d %[^\n]s", &i, str);
Instaed of scanf() use fgets() followed by sscanf().
Check return values of almost all functions with a prototype in <stdio.h>.
#include <stdio.h>
int main(void) {
int i;
char test[1024]; // I try to avoid identifiers starting with "str"
char tmp[10000]; // input buffer
// first line
if (fgets(tmp, sizeof tmp, stdin)) {
if (sscanf(tmp, "%d", &i) != 1) {
/* conversion error */;
}
} else {
/* input error */;
}
// second line: read directly into test
if (fgets(test, sizeof test, stdin)) {
size_t len = strlen(test);
if (test[len - 1] == '\n') test[--len] = 0; // remove trailing ENTER
// use i and test
printf("i is %d\n", i);
printf("test is \"%s\" (len: %d)\n", test, (int)len);
} else {
/* input error */;
}
return 0;
}

C writing in files problems with repeatable choice

Ok, thats half of my code, but i have problem and i cant fix it. For example i need to pick choice 2 it is adding something to file, i enter[ name, surname, date, gender ] press enter and program shows like menu again(2.Add to file) but this time automatically picks 2 choice and i need to write data another time and it happens all the time when picking choice 2. Please help me find solution of this problem.
#include <stdio.h>
#include <string.h>
#include <conio.h>
#include <windows.h>
#define N 15
struct date
{ int da_year;
int da_month;
int da_day;
};
struct studenti
{
int Nr;
char name[25];
char surname[25];
struct date dzd;
char dzimums;
}students[N] ;
int main()
{
sakums:
// FILE *fails_st;
char line[100];
char *ptk; char * end; int i;int sorted;
int g=0,ch,count=0;
int n;
int choice;
FILE *fails_st = fopen("studenti.txt", "r+");
/* errors ja neizdodas atveert failu */
if (fails_st == NULL)
{
printf("Error opening file!\n");
exit(1);
}
printf("\n2.Add to file");
scanf("%d",&choice);
if(choice==2){
/* write in file */
for (n=0; n<1; n++)
{
printf("%d. Ievadiet: vards, uzvards, datums, dzimums >", n+1);
scanf("%s",&students[n].name);
scanf("%s",&students[n].surname);
scanf("%d.%d.%d", &students[n].dzd.da_day, &students[n].dzd.da_month, &students[n].dzd.da_year);
scanf("%c",&students[n].dzimums);
}
fseek(fails_st, 0, SEEK_END);
for (i=0; i<n; i++)
fprintf(fails_st, " %d. %s %s %d.%d.%d %c\n", N+1, students[i].name,
students[i].surname, students[i].dzd.da_day,
students[i].dzd.da_month, students[i].dzd.da_year,
students[i].dzimums);
fclose(fails_st);
goto sakums;
}
getche();
return 0;
}
Your problem is likely that scanf happily does nothing if the format string that is its first parameter doesn't match the available input. That means it won't change the value of choice, so it will still be 2.
The cause of this is probably that what you input doesn't match your format strings. You can detect when this happens by checking the return value of scanf - it will return the number of variables written to, basically. If that is less than the number of format specifiers in your format string, something went wrong.
At that point, you probably want to consume all the available input (maybe something like int c; do { c = getchar(); } while (c != '\n' && c != EOF); for a simple program like yours) and then prompt the user again.
In particular, I believe your scanf("%c", ...) is likely the culprit: %c, unlike most scanf specifiers, will not ignore leading whitespace, but accept any character. So if you typed in "firstname lastname 1980.6.11 f", for example, the previous scanf call will just have consumed "6.11.1980", leaving " f" in the input buffer (note the space). Then the scanf with %c will read the space into the gender field, and leave the "f" in the input buffer. On the next go around, scanf("%d",&choice); will not do anything because "f" is not a valid number, choice will remain 2 and the "f" will get read as the first name on the next student entry, further confusing matters...
The solution is, I believe, to use scanf(" %c", ...); to explicitly consume leading whitespace.

Resources