What is the exact work, that the getchar() is doing? [duplicate] - c

This question already has answers here:
scanf() leaves the newline character in the buffer
(7 answers)
fgets doesn't work after scanf [duplicate]
(7 answers)
Closed 1 year ago.
Here, if I don't use getchar() the output is misbehaving:
What exactly is the getchar() doing here ?
And what is it holding until another input gets invoked ?
And how will the next input be invoked here in this case ?
My code:
//To take 3 students data using stucture which is user defined.
#include<stdio.h>
#include<stdlib.h>
//#include<conio.h>
struct student
{
char reg_number[200];
char name[200];
int marks_obt;
};
int main()
{
struct student stud1,stud2,stud3;
printf("Enter registration number of student 1 : ");
gets(stud1.reg_number);
printf("Enter name of student 1 : ");
gets(stud1.name);
printf("Enter marks of student 1 : ");
scanf("%d",&stud1.marks_obt);
system("cls");
//getchar();
printf("Enter registration number of student 2 : ");
gets(stud2.reg_number);
printf("Enter name of student 2 : ");
gets(stud2.name);
printf("Enter marks of student 2 : ");
scanf("%d",&stud2.marks_obt);
system("cls");
//getchar();
printf("Enter registration number of student 3 : ");
gets(stud3.reg_number);
printf("Enter name of student 3 : ");
gets(stud3.name);
printf("Enter marks of student 3 : ");
scanf("%d",&stud3.marks_obt);
system("cls");
printf("ID of student 1 is %s \n Name of student 1 is %s \n Marks obtained by stdent 1 is %d",stud1.reg_number,stud1.name,stud1.marks_obt);
printf("\n\n");
printf("ID of student 2 is %s \n Name of student 2 is %s \n Marks obtained by stdent 2 is %d",stud2.reg_number,stud2.name,stud2.marks_obt);
printf("\n\n");
printf("ID of student 3 is %s \n Name of student 3 is %s \n Marks obtained by stdent 3 is %d",stud3.reg_number,stud3.name,stud3.marks_obt);
//getch();
}

First of all, never use the gets(). It is deprecated from the C and C++ standards. The safe way would be to apply fgets():
char input[128];
if (fgets(input, sizeof input, stdin) == NULL) {
// Oops... input was incorrectly given, handle the error
return EXIT_FAILURE; // To quit
}
// Removing the trailing newline character
input[strcspn(input, "\n")] = 0;
You're facing an overlap when asking for another input from the user in the next gets() call because you hit the Return key as well when you finish typing with scanf(). A newline key is added at the end.
The getchar() takes the newline, so it is discarded and does the job you expect.

There are already comments and a correct answer that should be enough, but judging by your last comment it seems that you didn't yet understand what's going on.
This line:
scanf("%d",&stud1.marks_obt);
Parses an integer, for that you press Enter, when you do that a \n is added to the stdin buffer, and remains there, it is not parsed by scanf.
After that:
gets(stud2.reg_number);
Will parse that \n character and store it in stud2.reg_number, and the program moves on.
When you use getchar(), it parses the \n and leaves the stdin buffer empty again so the gets has nothing to parse and waits for your input, correcting the problem, it's still a flimsy solution, but it works in this particular case.
Moral of the story, don't mix scanf with gets, fgets at least, since, as stated, gets was removed from the standard in C11. The reason why some compilers still support it is beyond me.

Related

Why isn't this simple code waiting for student name (entered by user)? [duplicate]

This question already has answers here:
scanf() leaves the newline character in the buffer
(7 answers)
Closed 1 year ago.
This C code is not waiting for student name. It directly prints total student number. But when I comment out the first printf-scanf statement(or enter number of students:), then code is waiting for the user to enter student name.
#include <stdio.h>
int main()
{
char name[10];
int count;
printf("ENTER NUMBER OF STUDENTS:\n");
scanf("%d", &count);
printf("ENTER STUDENT NAME:\n");
scanf("%[^\n]%*c", &name);
printf("Total_Students: %d\n", count);
printf("NAME: %s\n", name);
return (0);
}
The second scanf is skipped because the newline character is being interpreted from the first scanf.
For instance, if you entered 2 for number of student, what is being entered is 2\n. The first scanf reads the number 2 and leaves the \n in the buffer which is being interpreted by the 2nd scanf.
You can simply add a space in the second scanf to get past this issue
scanf(" %[^\n]%*c", &name);
change the second scanf() argument to %s and it directly makes the last entry as NULL
.

Why is scanf causing infinite forlool [duplicate]

This question already has answers here:
scanf causing infinite loop in C
(2 answers)
Closed 2 years ago.
im just starting C and i dont know why this is happening. When i excuted the program it only stored 1 value in the service_code array. For some reason, the scanf() is keeping the loop counter ias 0. I couldn't find a solution. The scanf() is causing the forloop to to run infinitely. Does anyone know how to fix this?
#include <stdio.h>
#include <string.h>
int main() {
char name [100];
char str [10];
int discount = 0 ;
int age;
char service_codes[4][6];
printf("Welcome to Nelson Lanka Hospital \n");
printf("Our Services : \n SV105 - Doctor Channeling \n SV156 - Pharmacy \n SV128 - Laboratory \n SV100 - OPD \n \n");
printf("Enter your Details \n Name : ");
scanf("%[^\n]",name);
printf(" Enter age : ");
scanf("%d",&age);
printf(" Enter the Sevice code for the service you need : ");
scanf("%s", str);
strcpy(service_codes[0], str);
for(int i = 1; i<4; i++){
char yn [2] = "y";
printf("Do you need any other sevices? (y/n) : ");
gets(yn);
if (strcmp(yn, "n")==0){
break;
}
printf(" Enter the Sevice code for the service you need : ");
scanf("%s", str);
strcpy(service_codes[i], str);
printf("%s \t %s \t %d \n",service_codes[i],str,i);
}
for (int x = 0; x<4; x++){
printf("%s \n",service_codes[x]);
}
}
For some reason, the scanf() is keeping the loop counter i as 0.
You're probably having a buffer overflow that is altering the variables in the stack (such as the variable i). I see at least two points in your program where a buffer overflow may occur:
scanf("%s", str);: the array str only has room for 9 characters (plus 1 end null character used as a string terminator). If you type in a string longer than 9 characters (including the newline and carriage return characters that are appended when you hit ENTER) then scanf will corrupt the stack.
strcpy(service_codes[i], str);: each element in the array service_codes is defined to have 6 bytes each (room for 5 characters plus 1 end null terminator). By copying a string like this, in which str may be longer than service_code, you'll run into a buffer overflow.
C is a powerful language that allows you to do anything, even shooting at your own feet. You must be careful at every line you write in your code!

C program not taking user input [duplicate]

This question already has answers here:
How to do scanf for single char in C [duplicate]
(11 answers)
The program doesn't stop on scanf("%c", &ch) line, why? [duplicate]
(2 answers)
Closed 2 years ago.
i am a beginner in C programming. I was learning about the user inputs. The following piece of code:
#include <stdio.h>
#include <stdlib.h>
int main()
{
char grade;
printf("Enter you grade: ");
scanf("%c", &grade);
printf("Your grade is %c.", grade);
return 0;
}
does what I intend it to do i.e.
ask for the grade
display the grade
But when I modify the code to the following :
#include <stdio.h>
#include <stdlib.h>
int main()
{
int age;
printf("Enter you age: ");
scanf("%d", &age);
printf("You are %d years old.\n", age);
printf("-----------------------------\n");
double gpa;
printf("Enter your GPA: ");
scanf("%lf", &gpa);
printf("Your GPA is %f. \n", gpa);
printf("-----------------------------\n");
char grade;
printf("Enter you grade: ");
scanf("%c", &grade);
printf("Your grade is %c.", grade);
return 0;
}
it does the following:
asks for the age
displays the age
asks for the gpa
displays gpa
asks for grade
it doesnt display grade.
The output looks like:
Enter you age: 45
You are 45 years old.
-----------------------------
Enter your GPA: 4
Your GPA is 4.000000.
-----------------------------
Enter you grade: Your grade is
.
please suggest me what I am doing wrong.
When you enter your age, this is what is in the input buffer just before the scanf(%d) starts retrieving characters:
45<newline>
The scan(%d) skips any white space in the buffer (there isn't any), reads the 45, but leaves the newline. Then when you enter your GPA, this is what is in the input buffer just before the scanf(%lf) starts retrieving characters:
<newline>4<newline>
The scan(%lf) skips any white space in the buffer (the newline), reads the 4, but again leaves the newline. In other words, the leading newline doesn't matter if your next next scanf also skips whitespace such as moving from the first entry to the second.
But scanf(%c) does not skip white space. It simply reads the next character, which is a newline:
<newline>A<newline>
That's why tour period appears on the following line, it has read a character, but that character was the newline rather than the grade.
Section 7.21.6.2 The fscanf function, in the ISO C11 standard, has this to say on the first step of processing a conversion specifier (my emphasis):
Input white-space characters (as specified by the isspace function) are skipped, unless the specification includes a [, c, or n specifier.
A quick fix would be to manually skip whitespace yourself, something like:
printf("Enter your grade: ");
scanf(" %c", &grade);
printf("Your grade is %c.", grade);
as per that same section of the standard:
A directive composed of white-space character(s) is executed by reading input up to the first non-white-space character (which remains unread), or until no more characters can be read.

Why isn't my %[^\n] not working properly? [duplicate]

This question already has answers here:
scanf: "%[^\n]" skips the 2nd input but " %[^\n]" does not. why?
(6 answers)
The differences of scanf("%[^\n]",name); and scanf(" %[^\n]",name);
(2 answers)
scanf() leaves the newline character in the buffer
(7 answers)
Closed 5 years ago.
int main() {
char a[100];
printf("\nEnter 1st Sentence : ");
scanf("%[^\n]", a);
printf("\nSentence 1 : %s", a);
printf("\nEnter 2nd Sentence : ");
scanf("%[^\n]", a);
printf("\nSentence 2 : %s", a);
return 0;
}
My output:
Enter 1st Sentence : Testing 1st Sentence
Sentence 1 : Testing 1st Sentence
Enter 2nd Sentence :
Sentence 2 : Testing 1st Sentence
I'm basically checking %[^\n]. When I type the 1st sentence and press "Enter" key, it prints "Enter 2nd Sentence : " and then "Sentence 2 : " and then it prints the 1st sentence.
Because you did not read the Enter key from the input buffer, it is still there when the second scanf() asks for input. It then thinks you just pressed enter without typing any text.
Instead of scanf("%[^\n]", a), use this:
fgets(a, sizeof(a), stdin);
And just strip the trailing newline yourself.
There are multiple problems with scanf("%[^\n]", a):
You have a potential buffer overfow if reading a line longer than 99 bytes. You can prevent this with scanf("%99[^\n]", a).
You leave the newline in the input stream and it is still present for the next call where it causes the conversion to fail because the format must match at least one byte different from newline. You can prevent this by ignoring leading white space with scanf(" %[^\n]", a). Note the initial space in the format string.
You do not check if the conversion was successful. scanf() return the number of successful conversions. In your case it should return 1.
Here is the modified program:
#include <stdio.h>
int main(void) {
char a[100];
printf("\nEnter 1st Sentence: ");
if (scanf(" %99[^\n]", a) != 1)
return 1;
printf("\nSentence 1 : %s", a);
printf("\nEnter 2nd Sentence : ");
if (scanf(" %99[^\n]", a) != 1)
return 1;
printf("\nSentence 2 : %s", a);
return 0;
}

string input with spaces [duplicate]

This question already has answers here:
How do you allow spaces to be entered using scanf?
(11 answers)
Closed 6 years ago.
I'm trying to run the following code in the basic ubuntu gcc compiler for a basic C class.
#include<stdio.h>
struct emp
{
int emp_num, basic;
char name[20], department[20];
};
struct emp read()
{
struct emp dat;
printf("\n Enter Name : \n");
scanf("%s", dat.name);
printf("Enter Employee no.");
scanf("%d", &dat.emp_num);
//printf("Enter department:");
//fgets(dat->department,20,stdin);
printf("Enter basic :");
scanf("%d", &dat.basic);
return dat;
}
void print(struct emp dat)
{
printf("\n Name : %s", dat.name);
printf("\nEmployee no. : %d", dat.emp_num);
//printf("Department: %s", dat.department);
printf("\nBasic : %d\n", dat.basic);
}
int main()
{
struct emp list[10];
for (int i = 0; i < 3; i++)
{
printf("Enter Employee data\n %d :\n", i + 1);
list[i] = read();
}
printf("\n The data entered is as:\n");
for (int i = 0; i < 3; i++)
{
print(list[i]);
}
return 0;
}
I want the name to accept spaces.
The problem comes when I'm entering the values to the structures. I am able to enter the name the first time but the subsequent iterations don't even prompt me for an input.
I've tried using fgets, scanf("%[^\n]",dat.name) and even gets() (I was desperate) but am the facing the same problem every time.
The output for the 1st struct is fine but for the rest is either garbage, the person's last name or just blank.
Any ideas?
When reading a string using scanf("%s"), you're reading up to the first white space character. This way, your strings cannot include spaces. You can use fgetsinstead, which reads up to the first newline character.
Also, for flushing the input buffer, you may want to use e.g. scanf("%d\n") instead of just scanf("%d"). Otherwise, a subsequent fgets will take the newline character and not ask you for input.
I suggest that you experiment with a tiny program that reads first one integer number and then a string. You'll see what I mean and it will be much easier to debug. If you have trouble with that, I suggest that you post a new question.
The problem is that scanf("%[^\n",.. and fgets don't skip over any whitespace that may be left over from the previous line read. In particular, they won't skip the newline at the end of the last line, so if that newline is still in the input buffer (which it will be when the last line was read with scanf("%d",..), the scanf will fail without reading anything (leaving random garbage in the name array), while the fgets will just read the newline.
The easiest fix is to add an explicit space in the scanf to skip whitespace:
printf("\n Enter Name : \n");
scanf(" %19[^\n]", dat.name);
This will also skip over any whitespace at the beginning of the line (and blank lines), so may be a problem if you want to have a name that begins with a space.
Note I also added a length limit of 19 to avoid overflowing the name array -- if the user enters a longer name, the rest of it will be left on the input and be read as the employeee number. You might want to skip over the rest of the line:
scanf("%*[^\n]");
This will read any non-newline characters left on the input and throw them away. You can combine this with the prior scanf, giving you code that looks like:
printf("\n Enter Name : ");
scanf(" %19[^\n]%*[^\n]", dat.name);
printf("Enter Employee no. : ");
scanf("%d%*[^\n]", &dat.emp_num);
printf("Enter department : ");
scanf(" %19[^\n]%*[^\n]", dat.department);
printf("Enter basic : ");
scanf("%d%*[^\n]", &dat.basic);
This will ignore any spurious extra stuff that someone enters on a line, but will still have problems with someone entering letters where numbers are expected, or end-of-file conditions. To deal with those, you need to be checking the return value of scanf.
What you have tried was:-
scanf("%[^\n]",dat.name)
In this you forgot to specify the specifier.
You can try to use this:-
scanf ("%[^\n]%*c", dat.name);
or fgets() if you want to read with spaces.
Note:- "%s" will read the input until whitespace is reached.

Resources