Using 'fgets' to read in a char is just skipping when running - c++

the issue is in the read_in function when i use fgets to read in the users input for a band/singer it will just skip this line. I cant work out why this is happening? I did use scanf for this before but the issue is that if you do that when you enter a band name with a space e.g 'foo fighters' it will skip the next print name of reference line. Anyone know how to fix this?
#include <stdio.h>
#include <conio.h>
#define MAX 1000`enter code here`
int exit = 0; // Declaring a global variable
struct data { // using struct to put the data in an arrays
char band [48], cd [48], ref [16];
float cost;
int year;
} cata [MAX]; // declaring a struct variable
int read_in ( void )
{
int i = 0;
printf("\n");
while ( exit != 2 ) // while exit != 2 then ask the user to enter the information
{
printf("\nPlease Enter the Name of Band/Singer: ");
fgets(cata[i].band, 48, stdin);
printf("\nPlease Enter the Name of CD: ");
scanf("%s", &cata[i].cd);
printf("\nPlease Enter the Name of the Reference: ");
scanf("%s", &cata[i].ref);
printf("\nPlease Enter the cost: ");
scanf("%f", &cata[i].cost);
printf("\nPlease Enter the Year of Release: ");
scanf("%d", &cata[i].year);
printf("\nWrite another CD: [1] \nMain Menu: [2]\nYour choice: "); // Asking him a choice either write another one or go back to menu
scanf("%d", &exit);
i++;
}
exit = 0;
return i;
}
void print_out (void)
{
FILE *file_cata;
int i = 0;
printf("\n");
while ( exit != 2 )
{
file_cata = fopen ("catalogue.txt", "r"); // open the file and read
if (file_cata == NULL)
{
printf("Error: can't open files.\n");
}
else
{
while (!feof (file_cata))
{
fgets(cata[i].band, MAX , file_cata); // it will scanf the file and get the string and then print it out on screen
printf("%s", cata[i].band);
fgets(cata[i].cd, MAX, file_cata);
printf("%s", cata[i].cd);
fgets(cata[i].ref, MAX, file_cata);
printf("%s", cata[i].ref);
fscanf(file_cata, "%.2f" , cata[i].cost);
fscanf(file_cata, "%d", cata[i].year);
i++;
}
}
fclose (file_cata); // close file
printf("Read it again: [1] \nMain Menu: [2]\nYour choice: ");
scanf("%d", &exit);
}
exit = 0;
}
void save ( int num )
{
FILE *file_cata;
int i = 0;
printf("\n");
while ( exit != 2 )
{
file_cata = fopen ("catalogue.txt", "a"); // file append, so it will write at the end of the file
if (file_cata == NULL)
{
printf("Error: can't open files. \n");
}
else
{
while (i != num)
{
fprintf( file_cata, "\n");
fprintf( file_cata, "The name of Band/Singer: %s \n", cata[i].band);
fprintf( file_cata, "The name of CD: %s \n", cata[i].cd);
fprintf( file_cata, "The name of Reference: %s\n", cata[i].ref);
fprintf( file_cata, "The Cost: %.2f \n", cata[i].cost);
fprintf( file_cata, "The Year of Release: %d \n", cata[i].year);
i++;
}
}
fprintf( file_cata, "\n");
fclose (file_cata);
printf("Your data has been saved to the catalogue.\n\n");
printf("Save it again: [1] \nMain Menu: [2]\nYour Choice: ");
scanf("%d", &exit);
}
exit = 0;
}
void main ()
{
int num1 = 0;
int option = 0;
while ( option != 4 )
{
printf("The following options are availlable: \n");
printf("Read in data [1] \n");
printf("Print out catalogue to screen [2] \n");
printf("Save data to file [3] \n");
printf("Exit Program [4] \n");
printf("Enter your choice now: ");
scanf( "%d", &option);
if (option == 1)
num1 = read_in ();
if (option == 2)
print_out ();
if (option == 3)
save(num1);
printf("\n");
}
printf("\n*** Your program will end when you press ANY button. ***\n");
_getch();
}

The scanf is leaving the newline in the input buffer. Related question with a very good answer (Hint: don't use scanf; use fgets always, plus sscanf if you must convert that way.): Replacement of fflush(stdin)
This flushes the input buffer, which you should do before attempting to read another line (stolen from answer above):
while((c = getchar()) != '\n' && c != EOF)

Related

Why my code runs to infinite loop when I input a non integer from scanf? [duplicate]

I've a small C-program which just reads numbers from stdin, one at each loop cycle. If the user inputs some NaN, an error should be printed to the console and the input prompt should return again. On input of "0", the loop should end and the number of given positive/negative values should be printed to the console. Here's the program:
#include <stdio.h>
int main()
{
int number, p = 0, n = 0;
while (1) {
printf("-> ");
if (scanf("%d", &number) == 0) {
printf("Err...\n");
continue;
}
if (number > 0) p++;
else if (number < 0) n++;
else break; /* 0 given */
}
printf("Read %d positive and %d negative numbers\n", p, n);
return 0;
}
My problem is, that on entering some non-number (like "a"), this results in an infinite loop writing "-> Err..." over and over. I guess it's a scanf() issue and I know this function could be replace by a safer one, but this example is for beginners, knowing just about printf/scanf, if-else and loops.
I've already read the answers to the questionscanf() skips every other while loop in C and skimmed through other questions, but nothing really answer this specific problem.
scanf consumes only the input that matches the format string, returning the number of characters consumed. Any character that doesn't match the format string causes it to stop scanning and leaves the invalid character still in the buffer. As others said, you still need to flush the invalid character out of the buffer before you proceed. This is a pretty dirty fix, but it will remove the offending characters from the output.
char c = '0';
if (scanf("%d", &number) == 0) {
printf("Err. . .\n");
do {
c = getchar();
}
while (!isdigit(c));
ungetc(c, stdin);
//consume non-numeric chars from buffer
}
edit: fixed the code to remove all non-numeric chars in one go. Won't print out multiple "Errs" for each non-numeric char anymore.
Here is a pretty good overview of scanf.
scanf() leaves the "a" still in the input buffer for next time. You should probably use getline() to read a line no matter what and then parse it with strtol() or similar instead.
(Yes, getline() is GNU-specific, not POSIX. So what? The question is tagged "gcc" and "linux". getline() is also the only sensible option to read a line of text unless you want to do it all by hand.)
I think you just have to flush the buffer before you continue with the loop. Something like that would probably do the job, although I can't test what I am writing from here:
int c;
while((c = getchar()) != '\n' && c != EOF);
Due to the problems with scanf pointed out by the other answers, you should really consider using another approach. I've always found scanf way too limited for any serious input reading and processing. It's a better idea to just read whole lines in with fgets and then working on them with functions like strtok and strtol (which BTW will correctly parse integers and tell you exactly where the invalid characters begin).
Rather than using scanf() and have to deal with the buffer having invalid character, use fgets() and sscanf().
/* ... */
printf("0 to quit -> ");
fflush(stdout);
while (fgets(buf, sizeof buf, stdin)) {
if (sscanf(buf, "%d", &number) != 1) {
fprintf(stderr, "Err...\n");
} else {
work(number);
}
printf("0 to quit -> ");
fflush(stdout);
}
/* ... */
I had similar problem. I solved by only using scanf.
Input "abc123<Enter>" to see how it works.
#include <stdio.h>
int n, num_ok;
char c;
main() {
while (1) {
printf("Input Number: ");
num_ok = scanf("%d", &n);
if (num_ok != 1) {
scanf("%c", &c);
printf("That wasn't a number: %c\n", c);
} else {
printf("The number is: %d\n", n);
}
}
}
On some platforms (especially Windows and Linux) you can use fflush(stdin);:
#include <stdio.h>
int main(void)
{
int number, p = 0, n = 0;
while (1) {
printf("-> ");
if (scanf("%d", &number) == 0) {
fflush(stdin);
printf("Err...\n");
continue;
}
fflush(stdin);
if (number > 0) p++;
else if (number < 0) n++;
else break; /* 0 given */
}
printf("Read %d positive and %d negative numbers\n", p, n);
return 0;
}
The Solution: You need to add fflush(stdin); when 0 is returned from scanf.
The Reason: It appears to be leaving the input char in the buffer when an error is encountered, so every time scanf is called it just keeps trying to handle the invalid character but never removing it form the buffer. When you call fflush, the input buffer(stdin) will be cleared so the invalid character will no longer be handled repeatably.
You Program Modified: Below is your program modified with the needed change.
#include <stdio.h>
int main()
{
int number, p = 0, n = 0;
while (1) {
printf("-> ");
if (scanf("%d", &number) == 0) {
fflush(stdin);
printf("Err...\n");
continue;
}
if (number > 0) p++;
else if (number < 0) n++;
else break; /* 0 given */
}
printf("Read %d positive and %d negative numbers\n", p, n);
return 0;
}
try using this:
if (scanf("%d", &number) == 0) {
printf("Err...\n");
break;
}
this worked fine for me... try this..
the continue statement is not appropiate as the Err.. should only execute once. so, try break which I tested... this worked fine for you.. i tested....
When a non-number is entered an error occurs and the non-number is still kept in the input buffer. You should skip it. Also even this combination of symbols as for example 1a will be read at first as number 1 I think you should also skip such input.
The program can look the following way.
#include <stdio.h>
#include <ctype.h>
int main(void)
{
int p = 0, n = 0;
while (1)
{
char c;
int number;
int success;
printf("-> ");
success = scanf("%d%c", &number, &c);
if ( success != EOF )
{
success = success == 2 && isspace( ( unsigned char )c );
}
if ( ( success == EOF ) || ( success && number == 0 ) ) break;
if ( !success )
{
scanf("%*[^ \t\n]");
clearerr(stdin);
}
else if ( number > 0 )
{
++p;
}
else if ( number < n )
{
++n;
}
}
printf( "\nRead %d positive and %d negative numbers\n", p, n );
return 0;
}
The program output might look like
-> 1
-> -1
-> 2
-> -2
-> 0a
-> -0a
-> a0
-> -a0
-> 3
-> -3
-> 0
Read 3 positive and 3 negative numbers
I had the same problem, and I found a somewhat hacky solution. I use fgets() to read the input and then feed that to sscanf(). This is not a bad fix for the infinite loop problem, and with a simple for loop I tell C to search for any none numeric character. The code below won't allow inputs like 123abc.
#include <stdio.h>
#include <ctype.h>
#include <string.h>
int main(int argc, const char * argv[]) {
char line[10];
int loop, arrayLength, number, nan;
arrayLength = sizeof(line) / sizeof(char);
do {
nan = 0;
printf("Please enter a number:\n");
fgets(line, arrayLength, stdin);
for(loop = 0; loop < arrayLength; loop++) { // search for any none numeric charcter inisde the line array
if(line[loop] == '\n') { // stop the search if there is a carrage return
break;
}
if((line[0] == '-' || line[0] == '+') && loop == 0) { // Exculude the sign charcters infront of numbers so the program can accept both negative and positive numbers
continue;
}
if(!isdigit(line[loop])) { // if there is a none numeric character then add one to nan and break the loop
nan++;
break;
}
}
} while(nan || strlen(line) == 1); // check if there is any NaN or the user has just hit enter
sscanf(line, "%d", &number);
printf("You enterd number %d\n", number);
return 0;
}
To solve partilly your problem I just add this line after the scanf:
fgetc(stdin); /* to delete '\n' character */
Below, your code with the line:
#include <stdio.h>
int main()
{
int number, p = 0, n = 0;
while (1) {
printf("-> ");
if (scanf("%d", &number) == 0) {
fgetc(stdin); /* to delete '\n' character */
printf("Err...\n");
continue;
}
if (number > 0) p++;
else if (number < 0) n++;
else break; /* 0 given */
}
printf("Read %d positive and %d negative numbers\n", p, n);
return 0;
}
But if you enter more than one character, the program continues one by one character until the "\n".
So I found a solution here: How to limit input length with scanf
You can use this line:
int c;
while ((c = fgetc(stdin)) != '\n' && c != EOF);
// all you need is to clear the buffer!
#include <stdio.h>
int main()
{
int number, p = 0, n = 0;
char clearBuf[256]; //JG:
while (1) {
printf("-> ");
if (scanf("%d", &number) == 0) {
fgets(stdin, 256, clearBuf); //JG:
printf("Err...\n");
continue;
}
if (number > 0) p++;
else if (number < 0) n++;
else break; /* 0 given */
}
printf("Read %d positive and %d negative numbers\n", p, n);
return 0;
}
Flush the input buffer before you scan:
while(getchar() != EOF) continue;
if (scanf("%d", &number) == 0) {
...
I was going to suggest fflush(stdin), but apparently that results in undefined behavior.
In response to your comment, if you'd like the prompt to show up, you have to flush the output buffer. By default, that only happens when you print a newline. Like:
while (1) {
printf("-> ");
fflush(stdout);
while(getchar() != EOF) continue;
if (scanf("%d", &number) == 0) {
...
Hi I know this is an old thread but I just finished a school assignment where I ran into this same problem.
My solution is that I used gets() to pick up what scanf() left behind.
Here is OP code slightly re-written; probably no use to him but perhaps it will help someone else out there.
#include <stdio.h>
int main()
{
int number, p = 0, n = 0;
char unwantedCharacters[40]; //created array to catch unwanted input
unwantedCharacters[0] = 0; //initialzed first byte of array to zero
while (1)
{
printf("-> ");
scanf("%d", &number);
gets(unwantedCharacters); //collect what scanf() wouldn't from the input stream
if (unwantedCharacters[0] == 0) //if unwantedCharacters array is empty (the user's input is valid)
{
if (number > 0) p++;
else if (number < 0) n++;
else break; /* 0 given */
}
else
printf("Err...\n");
}
printf("Read %d positive and %d negative numbers\n", p, n);
return 0;
}
I've recently been through the same problem, and I found a solution that might help a lot of people. The function "scanf" leaves a buffer in memory ... and that's why the infinite loop is caused. So you actually have to "store" this buffer to another variable IF your initial scanf contains the "null" value. Here's what I mean:
#include <stdio.h>
int n;
char c[5];
int main() {
while (1) {
printf("Input Number: ");
if (scanf("%d", &n)==0) { //if you type char scanf gets null value
scanf("%s", &c); //the abovementioned char stored in 'c'
printf("That wasn't a number: %s\n", c);
}
else printf("The number is: %d\n", n);
}
}

How to clear input in C++ Console commands [duplicate]

Is there any way to hide user input when asked for in C?
For example:
char *str = malloc(sizeof(char *));
printf("Enter something: ");
scanf("%s", str);getchar();
printf("\nYou entered: %s", str);
// This program would show you what you were writing something as you wrote it.
// Is there any way to stop that?
Another thing, is how can you only allow certain characters?
For example:
char c;
printf("Yes or No? (y/n): ");
scanf("%c", &c);getchar();
printf("\nYou entered: %c", c);
// No matter what the user inputs, it will show up, can you restrict that only
// showing up if y or n are entered?
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <errno.h>
#define ECHOFLAGS (ECHO | ECHOE | ECHOK | ECHONL)
int set_disp_mode(int fd,int option)
{
int err;
struct termios term;
if(tcgetattr(fd,&term)==-1){
perror("Cannot get the attribution of the terminal");
return 1;
}
if(option)
term.c_lflag|=ECHOFLAGS;
else
term.c_lflag &=~ECHOFLAGS;
err=tcsetattr(fd,TCSAFLUSH,&term);
if(err==-1 && err==EINTR){
perror("Cannot set the attribution of the terminal");
return 1;
}
return 0;
}
int getpasswd(char* passwd, int size)
{
int c;
int n = 0;
printf("Please Input password:");
do{
c=getchar();
if (c != '\n'||c!='\r'){
passwd[n++] = c;
}
}while(c != '\n' && c !='\r' && n < (size - 1));
passwd[n] = '\0';
return n;
}
int main()
{
char *p,passwd[20],name[20];
printf("Please Input name:");
scanf("%s",name);
getchar();
set_disp_mode(STDIN_FILENO,0);
getpasswd(passwd, sizeof(passwd));
p=passwd;
while(*p!='\n')
p++;
*p='\0';
printf("\nYour name is: %s",name);
printf("\nYour passwd is: %s\n", passwd);
printf("Press any key continue ...\n");
set_disp_mode(STDIN_FILENO,1);
getchar();
return 0;
}
for linux
For the sake of completeness: There is no way to do this in C. (That is, standard, plain C without any platform-specific libraries or extensions.)
You did not state why you wanted to do this (or on what platform), so it's hard to make relevant suggestions. You could try a console UI library or a GUI library. You could also try your platform's console libraries. (Windows, Linux)

How to add statement if-else?

How to add if-else statement for "kodeprodi"?
Everytime I add if-else statement, the message "Lvalue required" always appears.
#include <iostream>
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
typedef struct {
char bp[13];
char nama[15];
int kodeprodi;
char namaprodi[10];
float ipk;
} mahasiswa;
int main()
{
char pil;
do {
mahasiswa mhs[10];
int i, n;
{
printf("Data Nilai Mahasiswa\n");
printf("Berapa banyak data = ");
scanf("%d", &n);
for(i = 0; i < n; i++) {
printf("Data mahasiswa ke-%d\n", i+1);
printf("Nomor BP: "); scanf("%s", &mhs[i].bp);
printf("Nama: "); scanf("%s", &mhs[i].nama);
printf("Kode Prodi: "); scanf("%d", &mhs[i].kodeprodi);
printf("IPK: "); scanf("%f", &mhs[i].ipk);
if (mhs[i].kodeprodi == 260) {mhs[i].namaprodi = "SI";}
else if (mhs[i].kodeprodi == 261) {mhs[i].namaprodi = "TI";}
}
//output
printf("No. BP Nama Kode Prodi Nama Prodi IPK \n");
for(i = 0; i < n; i++) {
printf("\n%2d %-10s %-9s %3d %3s %3.f\n",
i+1, mhs[i].bp, mhs[i].nama, mhs[i].nama,
mhs[i].kodeprodi, mhs[i].namaprodi, mhs[i].ipk);
}
}
printf("Repeat again? Y/N");
scanf("%s", &pil);
printf("\n\n");
} while ((pil == 'Y') || (pil == 'y'));
}
Even if in the statement if-else, I type like this
if(mhs[i].kodeprodi==260){namaprodi = "SI");
The error message is "Undefined symbol 'namaprodi'
I tweaked your code a bit. Got rid of unused conio.h, changed kodeprodi type to int (because char can only handle numbers -127..127), removed & from some scanf calls (because you should pass pointer to first character for %s formatter), deleted extra mhs[i].nama argument for printf.
Sorry, I completely didn't understood your code :-) My tweaks were semi-automatic! You should learn C programming better.
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
typedef struct {
char bp[13];
char nama[15];
int kodeprodi;
char namaprodi[10];
float ipk;
} mahasiswa;
int main() {
char pil;
do {
mahasiswa mhs[10];
int i, n;
{
printf("Data Nilai Mahasiswa\n");
printf("Berapa banyak data = ");
scanf("%d", &n);
for(i=0;i<n;i++) {
printf("Data mahasiswa ke-%d\n", i+1);
printf("Nomor BP: "); scanf("%s", mhs[i].bp);
printf("Nama: "); scanf("%s", mhs[i].nama);
printf("Kode Prodi: "); scanf("%d", &mhs[i].kodeprodi);
printf("IPK: "); scanf("%f", &mhs[i].ipk);
if(mhs[i].kodeprodi==260)
strcpy(mhs[i].namaprodi, "SI");
else if(mhs[i].kodeprodi==261)
strcpy(mhs[i].namaprodi, "TI");
}
//output
printf("No. BP Nama Kode Prodi Nama Prodi IPK \n");
for(i=0;i<n;i++) {
printf("\n%2d %-10s %-9s %3d %3s %3.f\n", i+1, mhs[i].bp, mhs[i].nama, mhs[i].kodeprodi, mhs[i].namaprodi, mhs[i].ipk);
}
}
printf("Repeat again? Y/N");
scanf("%s", &pil);
printf("\n\n");
} while ((pil == 'Y') || (pil == 'y'));
return 0;
}
For a quick fix, use:
if(mhs[i].kodeprodi==260){strncpy(mhs[i].namaprodi, "SI", 9);
strncpy() is needed to copy the contents into namaprodi.
namaprodi is a member of struct mahasiswa, so you can't access it directly.
But better use std::string instead.
Also, as #BoPersson mentioned, char kodeprodi; can't hold 260, so you'll better to convert that to an int.

Inotify - event->name gives subdirectories, not the main directories

I have been writing a program to print the name of the file being accessed and the time the file was accessed. Basically, instead of getting the file path name that I type in, I am getting the names of all the subdirectories of the file. I strongly suspect that it has something to do with the event->name that I am using toward the end of the program. Is there some other function I should be using instead?
The code is as follows:
string filename;
printf("Please enter the file path name: ");
getline(cin, filename);
/*Create a List<string> for multiple files to be entered*/
list<string> stringlist;
list<string>::iterator it;
stringlist.push_back(filename);
it = stringlist.begin();
while(filename != "exit")
{
/*Check whether files exists. Prompt user to re-enter filename*/
while(FileExists(filename) == false )
{
printf("File %s does not exist. Try again.\n", filename.c_str());
printf("Please enter the file path name: ");
getline(cin, filename);
}
printf("Please enter the next file: ");
getline(cin, filename);
if(filename != "exit")
stringlist.push_back(filename);
}
int index = 0;
wd = 0;
length = read(fd, buffer, BUF_LEN);
while(i < length) {
struct inotify_event* event = (struct inotify_event * ) &buffer[i];
if(event->mask & IN_ACCESS)
{
log.WriteFile(event->name);
}
i+= EVENT_SIZE + event->len;
}

How to read a string file from second line in C?

This code reads characters in a file and calculates length of characters. How i can read from second line and ignore read from first line?
this is part of my code:
int lenA = 0;
FILE * fileA;
char holder;
char *seqA=NULL;
char *temp=NULL;
fileA=fopen("d:\\str1.fa", "r");
if(fileA == NULL) {
perror ("Error opening 'str1.fa'\n");
exit(EXIT_FAILURE);
}
while((holder=fgetc(fileA)) != EOF) {
lenA++;
temp=(char*)realloc(seqA,lenA*sizeof(char));
if (temp!=NULL) {
seqA=temp;
seqA[lenA-1]=holder;
}
else {
free (seqA);
puts ("Error (re)allocating memory");
exit (1);
}
}
cout<<"Length seqA is: "<<lenA<<endl;
fclose(fileA);
Make a counter of how many \n you have seen,and when ==1 goto read from 2nd line.
int line=0;
while((holder=fgetc(fileA)) != EOF) {
if(holder == '\n') line++;
if(holder == 1) break; /* 1 because count start from 0,you know */
}
if(holder == EOF) {
//error:there's no a 2nd
}
while((holder=fgetc(fileA)) != EOF) {
// holder is contents begging from 2nd line
}
You can make it more simple by using fgets():
Make one call and ignore it(by don't discard the result-value,for error-checking);
Make second call, and begging reading from this.
NOTE: I'm considering C language here.
There is a tiny mistakes about the last answer.
I corrected and here is my code:
#include <stdio.h>
#include <stdlib.h>
#define TEMP_PATH "/FILEPATH/network_speed.txt"
int main( int argc, char *argv[] )
{
FILE *fp;
fp=fopen(TEMP_PATH, "r");
char holder;
int line=0;
while((holder=fgetc(fp)) != EOF) {
if(holder == '\n') line++;
if(line == 1) break; /* 1 because count start from 0,you know */
}
if(holder == EOF) {
printf("%s doesn't have the 2nd line\n", fp);
//error:there's no a 2nd
}
while((holder=fgetc(fp)) != EOF && (holder != '\n' )) {
putchar(holder);
}
fclose(fp);
}