Usage of two gets() in C++ - c++

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.

Related

Variable is getting assigned automatically

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]);

c++: cin.getline() cutting off input before specified carriage return

I'm trying to figure out how to use cin.getline() correctly and have run into a problem that I can't find an answer to.
I'm doing an assignment for a course I'm taking, and I need to be able to use cin to get whole lines of text from the user, including whitespaces. We can't use strings, we have to use character arrays (that's a requirement for the assignment). I decided to just use cin.ignore() and cin.getline(ARRAY_NAME, '\n').
Here's my problem: cin.getline() seems to be picking up the white spaces fine, but for some reason it's cutting off my line and only storing the first 9 characters that are being input.
Here's the relevant code (the stuff related to the use of "cin" is isolated to the "menu" function I'm calling from main that gets input from the user so I don't think I need to trouble everyone with the rest of it):
#include<iostream>
#include<cstring>
using namespace std;
void menu(){
char name[30];
char description[50];
char articleTitle[50];
cin.clear();
cin.ignore(); // Idk if both clear and ignore are necessary here
cout << endl << "Enter name: ";
cin.getline(name, '\n');
cout << endl << "Enter description: ";
cin.ignore();
cin.getline(description, '\n');
cin.ignore();
cin.getline(articleTitle, '\n');
cin.ignore();
It's using all this stuff to build a class object and add it to a list, and it's supposed to print a success message if it works that says something like
cout << endl << "you added " << name << " to the list" << endl;
but what's happening is, if I enter more than 9 characters for any of those three character arrays, it prints the success message with "name" trimmed down to 9 characters and then exits the program.
I don't think it could have anything to do with the rest of my program because I don't edit any of the character arrays in any way after they're input, and it only breaks when I enter more than 9 characters for any of the three. If I enter 9 for "name" and 9 for "description" it'll still break as soon as I enter 10+ for "articleTitle"
Does anyone know what might be causing this? Thanks in advance

Clear entire line from cin instead of one character at a time when the user enters bad input

I have a question on some commands for cin. I'm still very new to c++ so bear with me.
I'm doing a simple calculation program where the user inputs a value and the program does a calculation with the input. I'm attempting to create a loop that checks the input to ensure the user inputted and number. After some research I found that using cin.clear and cin.ignore will clear the previous input so the user can input a new value after the loop checks to see if its not a number. It works well, except when the user inputs a word larger then 1 letter. It then loops and removes each letter one at a time until the previous cin is cleared. Is there a way to remove the entire word rather then one character at a time? I feel I have incorrectly interpreted what the cin commands actually do.
Here is the code in question:
//Ask the user to input the base
cout << "Please enter the Base of the triangle" << endl;
cin >> base;
//A loop to ensure the user is entering a numarical value
while(!cin){
//Clear the previous cin input to prevent a looping error
cin.clear();
cin.ignore();
//Display command if input isn't a number
cout << "Not a number. Please enter the Base of the triangle" << endl;
cin >> base;
}
I think you could get the answer in many ways on the net. Still this works for me:
#include <iostream>
#include <limits>
using namespace std;
int main() {
double a;
while (!(cin >> a)) {
cin.clear();
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
cout << "Wrong input, retry!" << endl;
}
cout << a;
}
This example is simpler than the one linked in the comments since you are expecting input from the user, one input per line.

cin.get(); doesn't work when I put it in a if statement

I used cin.get() to get the program to pause and wait for user input, and it works fine. The moment I put it in an if statement, it just skips that "wait" period and continues on with the code? How can I solve this. Here is the section that is not working.
do
{
cout << "\n\n\nEnter the number of one of the following and I will explain!\n";
cout << "1.integer 2.boolian 3.floats 4.doubles 5.character";
cout << "\n\n[when you are done type 'done' to continue]\n\n";
cin >> option;
if (option = 1);
{
cout << "\nInteger is the variable abbreviated as 'int' this allows C++ to only";
cout << "\nreadwhole and real numbers \n\n";
cin.get(); //this is the part where it just skips.. it should wait
}
} while (var = 1);
The problem is that cin >> option will extract whatever integer is in the input stream but will leave the following newline character (which is there from hitting enter after typing in the value). When you do cin.get() it is simply extracting that newline character which is already there. Like so many other questions like this, the solution is to empty the input stream after you've extracted into option:
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
You are also using assignment (=) where you should be comparing for equality (==).

getline(cin.name) gets skipped

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().