Click here to Skip to main content
15,888,461 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Question:
Write a program to take data of student as input by the help of
structure student variable.
Do some changes with it.(by using pointers)
And print it.
Problem 1;
I was practicing the structures in C and encounter the problem of (Enter taken by input functions as an input).
after debugging i found that roll and gender is taking enter as an input
So I place a fflush(stdin) between
fgets(std->name, 20, stdin);

and
scanf("%d", &(std->roll));

Later I found that gender is still taking Enter as an input
So I place fflush(stdin) between
scanf("%d", &(std->roll));

and
scanf("%c", &(std->gender));


While taking the input of Second student i found that now name of the second student is taking enter and roll and gender taking garbage vlaue.
So, finally placed fflush(stdin) above
this
fgets(std->name, 20, stdin);

Isn't there any way to resolve this enter issue so that we don't have to think where to place fflush(stdin) by debugging again and again.
Problem 2;
How this buffer input used by the input functions and where actually is this buffer input located (is it in the stack or heap) or in both.

What I have tried:

Header and Global Variables
#include <stdio.h>
struct student
{
    char name[20];
    int roll;
    char gender;
};
void input(struct student *std);
void change(struct student *std);
void display(struct student std);


Main function
int main()
{
    struct student Stu1, Stu2;
    
    input(&Stu1);
    change(&Stu1);
    display(Stu1);

    input(&Stu2);
    change(&Stu2);
    display(Stu2);

    return 0;
}


Input Function : IN THIS FUNCTION I HAVE USED THE FFLUSH(STDIN);
void input(struct student *std)
{
    fflush(stdin);
    fgets(std->name, 20, stdin);
    fflush(stdin);
    scanf("%d", &(std->roll));
    fflush(stdin);
    scanf("%c", &(std->gender));
}


Change function
void change(struct student *std)
{
    std->roll += 5;
    printf("\n");
}


Display function
void display(struct student std)
{
    printf("%s", std.name);
    printf("%d\n", std.roll);
    printf("%c\n", std.gender);
}
Posted
Updated 7-Oct-22 6:37am
v4

Unfortunately this is a feature of the scanf function. The function scans the input for information separated by whitespace, which it uses to delimit fields. If a newline character is left in the input stream, then the next scanf request will read that and assume that there is a null field entered. Flushing the stream, or using gets to read the newline, are the simplest ways round the problem.
 
Share this answer
 
You should be aware that fflush(stdin) as per the C standard is undefined behavior, and should probably be avoided.

If you are using Linux, take a look at getline(3) - Linux manual page[^] which will read an entire line of input at once, including the terminating new-line. You will then have to parse the input string for yourself, but that also means you have the opportunity to handle unexpected input gracefully. Don't forget to free() the buffer when you're done.

If you are using Windows, then AFAIK you are limited to fgets() or scanf(), or you could google for something like "windows C getline alternative" and use one of the solutions provided there.
 
Share this answer
 
The previous answers give the necessary information. I would summarize by stating you should pick one way to obtain your input and then stick with it. In my opinion, fgets is the best function to use if you accept your input one line at a time because it will accept the newline character(s). Here is its documentation : cplusplus.com - fgets[^]. Then you can use cplusplus.com - atoi[^] to convert the string to an integer value. Be aware that the newline will be contained in the returned string. That means when you get the string as an input you will need to remove it from the buffer. I usually use strchr to do this : cplusplus.com - strchr[^]. In fact, I do this so often that many years ago I made a little function to locate and remove a character. Here it is :
C++
void RemoveChar( char * buffer, int rmvchr )
{
    char * p = strchr( buffer, rmvchr )
    if( p )
       * p = 0;   // character was located - null it
}
You can call this to remove the newline character from your input string and you will be left with what you are after. You don't need to do that when accepting an integer because atoi will stop conversion when it is found and when you accept a single character you can ignore it yourself because your code will probably look something like this :
C++
std.gender = buffer[ 0 ];
 
Share this answer
 
Comments
Parth Vijay 8-Oct-22 6:03am    
So, i came to point where i find that fgets is much better than scanf..
Bcoz fgets takes '\n' in its string when we press enter which we can remove by making a function something like u have made and on the other side scanf stops taking an input when it encounters an enter key and the pressed enter key is left in the buffer which will create a problem for the upcoming input function (scanf,fgets,gets etc). So, to remove this problem what i did i just found the definition of the scanf fucntion in the (stdio.h) file by the help of debugger(step in feature) and added this fflush(stdin) before returning anything...

And i run the program it is working and i dont have to care now where to add this fflush(stdin) statement..
i want to ask if this is correct approach. means like changing the original code will affect me in future?
Rick York 8-Oct-22 14:27pm    
In my opinion, no. As I wrote, I prefer to use fgets because I do not want to ever have to concern myself with flushing the stream. I always write code that accepts input from a file so that's another reason I never use scanf. You might want to have a look at the function sscanf. It is scanf that operates on a string.
Since C++ was also asked for as a solution, you could also solve it this way.
C++
#define STRLEN 20

typedef struct {
	char name[STRLEN];
	int roll;
	char gender;
} student;

void change( student &std);

void display( student &std)
{
   std::cout << std.name << ", " << std.roll << ", " << std.gender << "\n";
}

void clrinput()
{
   if (std::cin.fail()) {
      std::cin.clear();
      std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
   }
}

void input( student &std)
{
	clrinput();
	std::cin.getline(std.name, STRLEN);
	clrinput();

	std::cin >> std.roll;
	clrinput();

	std::cin >> std.gender;
	clrinput();
}

C++
int main()
{
	student Stu1, Stu2;

	input(Stu1);
	change(Stu1);
	display(Stu1);

    // ... 
}

Actually, all of this belongs in one class, but it works just as well.
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900