I was making a project that gets students' names, roll numbers & marks and returns percentage or grade according to need of user. I made a function using for loop to assign details(name, etc.) to variable but during change of for loop's argument, program was assigning ""(null) to the first variable in execution part. Am I missing any code here?
#include <iostream>
#include <stdio.h>
using namespace std;
class Data
{
public:
int Rno[3], phy[3], mat[3], chem[3];
char name[3][100];
void getInfo()
{
for(int i = 0; i < 3; i++)
{
cout << "Enter your name: ";
gets(name[i]);
cout << "Enter your Roll number: ";
cin >> Rno[i];
cout << "Enter your Physics marks: ";
cin >> phy[i];
cout << "Enter your Maths marks: ";
cin >> mat[i];
cout << "Enter your Chemistry marks: ";
cin >> chem[i];
}
};
};
int main()
{
Data d;
d.getInfo();
puts(d.name[1]);
}
First an explanation. Then some options to address the problem.
The problem is that you are mixing line-oriented input (gets()) with formatted input (cin >> ....) on the same input device/stream.
Such functions treat whitespace - particularly newlines - differently. And, because of that, you can get unexpected interactions. In this case, cin >> chem[i] will read an integral value, stop when it encounters a newline, leave the newline character waiting to be read. Then gets() - in the next iteration of the loop - will encounter the newline, and return immediately (hence the "null", to use your description).
OK; that's the explanation. What to do about it?
The solution is not to mix such styles of input. One option consistently use line oriented input to read EVERYTHING as a string, and then separately parse the string.
Some people will suggest approaches that involve discarding (or "flushing") the offending newlines. That approach doesn't work well if your input is complex (e.g. lots of different statements reading from the same stream in different ways) because it is necessary to ensure EVERY stray newline is discarded. It is also error-prone - you can unintentionally discard input your program needs to read.
Also avoid using gets() like the plague. It has been removed from recent C standards for a reason - it is inherently unsafe.
There are various ways using C++ streams (like cin) to safely read strings and other types. For example, if some_str is of type std::string, then std::getline(std::cin, some_str) can be used to read a complete line of input. std::getline() also has the advantage that it can read a string of arbitrary size. But, still, avoid using std::getline(cin, some_str) and streaming input (cin >> ...) on the same stream - because they STILL handle newlines differently.
Problem is with not flushing cout. In your case inside the loop cout must be flushed before calling gets .
cout << "Enter your name: "<<endl; // This cout should be flushed properly **with** new line character
gets(name[i]);
From #ProXicT comment
cout << "Enter your name: "<<flush; // This cout should be flushed properly **without** new line character
gets(name[i]);
Related
Updated to describe the issue more accurately
C++ Language
I am trying to use a nested if if statement for learning purposes (tutorial following along with). I am aware the logical && operator would be ideal for this situation. Anyways...
The nested If If statement is skipping the user's chance to input data for the second question when the first guess equals the first answer. When the first guess is incorrect, everything runs as intended (both questions and user input request execute)
I could be mistaken but I feel everything is on par with the tutorial yet I keep encountering the issue I mentioned. Anyone got an answer? :)
Thanks :)
#include <iostream>
#include <string>
int main ()
{
std:: string variable_one_guess;
std:: string variable_two_guess;
std:: string variable_one_answer = "The answer for one";
std:: string variable_two_answer = "The answer for two";
std:: cout << "Guess the variable one value\n";
std:: cin >> variable_one_guess;
std:: cout << "Guess the variable two value\n";
std:: cin >> variable_two_guess;
if (variable_one_guess == variable_one_answer) // I am aware I can just combine both if statements using the logical
// && operator but I need this to work for learning purposes
{
if(variable_two_guess == variable_two_answer)
{std:: cout << "Correct!\n";}
}
}
Quentin correctly brought the getline function to my attention which works.
cin reads a single, whitespace-separated word. So I had to replace cin the the getline function.
//code
std:: cin >> variable_one_guess;
// code
std:: cin >> variable_two_guess;
//code
was replaced as
//code
getline(std::cin, variable_one_guess);
// code
getline(std::cin, variable_two_guess);
//code
I am starting to learn C++ and I am trying to create a program that asks the user to add values for all primitive types in C++, here is what I have written so far:
#include <iostream>
using namespace std;
int main()
{
bool empty_bool;
char empty_char;
int empty_int;
float empty_float;
double empty_double;
cout << "Please enter a value for all inbuilt primitive types in C++" << endl;
cout << "Boolean:";
cin >> empty_bool;
cout << "Char";
cin >> empty_char;
cout << "Int";
cin >> empty_int;
cout << "float";
cin >> empty_float;
cout << "double";
cin >> empty_double;
}
The problem is that my program takes the input of boolean but then it just prints the rest of the variable names but it doesn't allow to take the value for the said variable and I can't figure out why, what am I doing wrong here?
After doing any input, cin will contain a result condition. Reading invalid input will put the input stream cin into a fail state; typically, you are supposed to check that by evaluating cin in a boolean context:
if (cin >> empty_int)
cout << empty_int; // empty_int here is not empty anymore
else
cout << "error";
When reading an inappropriately formatted value for bool (as mentioned in comments, it must be 0 or 1 or true or false depending on the boolalpha flag), cin remembers its error state, and will not do any further input until it is reset:
cin.clear();
Note by user4581301:
Note that clear does not remove the offending data from the stream. Depending on what was read and how before the failure, you probably have something in the stream that will cause the exact same error again. If so, remove it before continuing, using one of the following ideas:
use std::istream::ignore (like here)
read it into something permissive like a std::string
or whatever best fits your usage
When it comes to creating a program based on a set of instructions, I do pretty well in designing the pseudo-code, implementing the actual code. What I feel like I lack is checking for users' input (whether it's valid or invalid). As I practiced programming, I created my own way for checking for validating users' input. But the code is lengthy and I feel like it's insufficient (I'll explain why). I wanted to know if there is a better way to check for users' input. And how do other programmers implement their code.
This is how I validate users' input:
if(cin.fail()) {
cout << "Invalid Input" << endl;
cout << "Now Exiting..." << endl;
return;
}
// I didn't know how to skip a line while in code
while(input < 0) {
cout << "Invalid Input" << endl;
cout << "Enter radius: " << endl;
cin >> input;
if(cin.fail()) {
cout << "Error: Invalid Input" << endl;
cout << "Now Exiting..." << endl;
return;
}
}
The reason why I exit out when cin fails to store the value into the variable separately (line 1 - 5, line 11 -15) is because if I add the cin.fail() to the while condition and attempt to input a letter, it begins a infinite loop. I did a little research and I saw you have to cin.sync(), then cin.clear(). But I still get the infinite loop.
Here is the code:
do {
cin.sync()
cin.clear();
cout << "Enter radius: ";
cin >> input;
} while(input < 0 || cin.fail());
If I'm doing something wrong, it would very helpful to see better ways to validate user's input.
I would not recommend using std::cin, since it leaves all remaining user input after the first found instance of whitespace in the input buffer. This will create problems unless you remove the remaining characters using cin.ignore(). It is generally seen as better practice to use getline(), which will get all the characters up to the newline character. If you do choose to use std::cin, you will need to use cin.ignore() to remove the remaining characters, and cin.clear() to reset cin's fail bit so the while conditional will work properly the next time through the loop.
Below is how I would solve the problem. It uses getline() to get all the characters, and a stringstream to convert the string to an int. Notice you need to clear the stringstream's fail bit just like with cin to make sure the conditional works correctly when you do ss >> result in the while conditional.
std::cout << "Enter radius: ";
getline(std::cin, input);
std::stringstream ss(input);
while(!(ss >> result)) {
std::cout << "Invalid Input" << std::endl;
std::cout << "Enter radius: ";
getline(std::cin, input);
ss.clear();
ss << input;
}
Below I'll also include some code to solve the problem using std:cin. I still recommend using getline() though. Note: std::numeric_limits::max() is used to specify how many characters to remove from the input buffer. Using this instead of your own arbitrary number is a better practice, since you can't know for certain how many characters the user will enter. cin.ignore() will remove all the characters up to the given number or until it reaches an instance of the character provided as its second parameter, which in this case is newline ('\n').
std::cout << "Enter radius: ";
std::cin >> result;
while(std::cin.fail()) {
std::cout << "Invalid Input" << std::endl;
std::cout << "Enter radius: ";
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::cin >> result;
}
The problem of input validation is an easy form of parsing.
There are language-classes (in the field of formal language theory) that express the complexity of your input. Those classes are called regular, context-free, and turing-complete.
You have to consider all your possible inputs, that your program might receive and decide whether your program should accept them or not. The language classes help you to decide what kind of input validation you need.
if the language is regular (as it is in your case) you can use regular expressions to validate the input.
A context-free language for example would be a math-formula. You cannot count the number of parentheses with a regular expression. Therefore it is impossible to check ((a+b) * (c+d)) has the right amount of parentheses with a regular expression.
Up to now these are hints on what you should be doing, when programming comes more naturally to you.
For the sake of simplicity well do a very constrained regular expression like parsing by hand.
what you actually want to do in pseudo code:
do {
std::cout << "Please enter radius: ";
line = read_a_line_from(std::cin) // separated by '\n' the newline
if (false == really_read_a_line(line)) {
/* error handling for std::cin, dealing with i.e.: the fail bit */
break; /* exit the loop */
}
if (line == "exit") { // give the user an explicit exit, to quit gracefully
exit(SUCCESS); /* exit the program */
}
if (false == is_a_number(line)) {
/* we read something that isn't a number */
/* we should tell the user he should do as we asked */
continue; /* jump back to the beginning of the loop */
}
unsigned num = convert_number(line);
unsigned area = calculate_area(num); /* do something with your input */
} while (true);
exit(FAILURE);
The code here is not too specific on purpose that you see what you could be doing in places, still leaving out the actual implementation (for your exercise). Please note that a simple way of checking whether a line is actually a number is by converting. However not all things to parse should be checked for validity and processed at the same time.
See Also (especially the examples):
http://en.cppreference.com/w/cpp/string/basic_string/getline
http://en.cppreference.com/w/cpp/string/basic_string/stol
how to check if given c++ string or char* contains only digits?
do {
cin.sync()
cin.clear();
cout << "Enter radius: ";
cin >> input;
} while(input < 0 && cin.fail());
I am learning about classes in C++. I made a simple program using the concept of classes. In the program I need the person to enter the details of the book. Here is that function:
void Book::add(){
cout << "Enter name of Book: ";
gets(book_name);gets(book_name);
cout << "\n\nPlease enter the book id: ";
cin >> book_id;
cout << "\n\nThank you the book has been added.";
total++;
input = getchar();
getchar();
}
Notice in the third line I have to use two gets to get the user input. If I use one gets
this is the output. It just skips the gets statement. Similarly at other places also I have to use two getchar statements. I was able to find the answer for that on SO itself. Ex Why my prof. is using two getchar. I couldn't find the answer for two gets statements, though. Here is the complete code in case it is required.
That is because you have a trailing new line (from Enter) character remaining on the stream that is not read by the first read operation. So the first gets(book_name) will read that and continue to the next request for input.
use getline to remove any remaining offending input from the stream.
void Book::add(){
string garbage;
getline(cin,garbage); // this will read any remaining input in stream. That is from when you entered 'a' and pressed enter.
cout << "Enter name of Book: ";
gets(book_name);
getline(cin,garbage); // this will read any remaining input in stream.
cout << "\n\nPlease enter the book id: ";
cin >> book_id;
Anyways just use the safer way of reading input from streams
cin >> book_name;
instead of gets. Then you will not have such problems.
if you want to read space separated inputs in to one string the use std::getline (like I did for garbage above)
std::getline(cin,book_name);
cin and cout are from <iostream> and gets comes from <cstdio>. It's not good idea to mix those two if you don't exactly know how those two work and what is the difference.
Better idea is to use cin.getline()
cin.getline(char* s, streamsize n );
The second parameter is the maximum length of the input.
I call a function from a function in C++ that has the line getline(cin,name) where name is a string. the first time through the loop, the program does not wait for input. It will on all other passes through the loop. Any ideas on why?
void getName (string& name)
{
int nameLen;
do{
cout << "Enter the last Name of the resident." << endl << endl
<< "There should not be any spaces and no more than 15"
<< " characters in the name." << endl;
getline(cin,name);
cout << endl;
nameLen = name.length();// set len to number of characters input
cout << "last" << name << endl;
}
while (nameLen < LastNameLength);
return;
}
Make sure there isn't left overs since the last time you read something from cin, like:
In an earlier point in your program:
int number;
cin >> number;
The input you give:
5
Later in the program:
getline(cin,name);
and getline will seem to not be called, but rather it collected the newline from the last time you took input because when you use cin >> it leaves new lines.
It may be because of the input stream. The getline function stops reading input after is receives the first newline char. If for example there are multiple newlines within the buffer of std::cin - the getline will return every time it encounters one.
Check the input you are expecting.
Do you have any:
cin << variableName;
lines of code? I ran into getline() skipping run-time errors when I was using:
cin << intvariable and subsequently getline(cin, variable).
This is because the cin stream object holds a buffer of input. When you enter the newline character I assume it is trunacated from the stream going to the variable asisgnment, yet is still contained within the cin object instance itself.
One workaround I used is cin.ignore(); after the cin << integer statement.
Another user mentioned parsing all input from getline into integers, floats - not root beer -, and strings. Good luck and check your code for the dual use of cin & getline().