Getting whole line from files - c++

My program Can read strings and integer, but the problem is when I add spaces for strings like names it does not execute the viewOrder() function. I am New to programming and start learning c++ as my frist language at 19 years old, hoping that someone can help me. I am doing an uniform ordering system.
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
struct orderDetails{
string name;
int studentNumber;
string address;
string dressCode;
int quantity;
};
void takeOrder(){
orderDetails order;
ofstream file ("database.dat" , ios::app);
cin.ignore();
cout << "Enter name: ";
getline(cin,order.name);
cout << "Enter Student Number: ";
cin >> order.studentNumber;
cin.ignore();
cout << "Enter Address: ";
getline(cin,order.address);
cout << "Enter Dress Code: ";
cin >> order.dressCode;
cout << "Enter Quantity: ";
cin >> order.quantity;
file << order.name << endl
<< order.studentNumber << endl
<< order.address << endl
<< order.dressCode << endl
<< order.quantity << endl;
file.close();
}
void viewOrder(){
ifstream database("database.dat");
orderDetails order;
while(database >> order.name >> order.studentNumber >> order.address >> order.dressCode >> order.quantity){
cout << endl << order.name << endl << order.studentNumber << endl << order.address << endl << order.dressCode << endl << order.quantity << endl;
}
}
int main(){
cout << "1.Take Order \n2.View Order \n3.Exit \nPlease Choose A Number: ";
int choice;
cin >> choice;
switch(choice){
case 1:
system("CLS");
takeOrder();
break;
case 2:
system("CLS");
viewOrder();
break;
default:
break;
}
return 0;
}

This is an old problem. You need to learn about the difference between formatted and unformatted input.
If you have a line of text like
abc def
and you read this into std::strings with
inputFileStream >> s1 >> s2
Then the input "abc" and "def" will be read into the to string-variables. Ok. But, the newline ('\n') at the end of the line will not be consumed. If you write an additional
inputFileStream >> s1 >> s2
to read the next line, then the inserter operator >> will skip the whitespace '\n' and read the strings as you would expect.
But, if you use std::getline after the initial formatted input, then, and remember that there is still a not-consumed '\n' at the end of the line, only an empty string and the newline will be read.
To overcome this situation, you can use std::ws. Please see here for a description. So, you simply add this in your std::getline statement.
Like this:
std::getline(ifs >> std::ws, line);
This will eat up all white spaces (including '\n') in front of the next text that you want to read.
To explain it better. This is a nested statement. So, first ifs >> std::ws is executed. This operation returns again ifs and then the std::getline will be done. You can of course also use ifs >> std::ws outside of the std::getline. That is in most cases better than calling ignore.
But remember. This is only necessary, if you switch from formatted to unformatted input.

Related

C++ - How to know where to put cin.ignore

I have a code from my friend and we do not know how to use cin. ignore very well.
Our problem is that we are using do while and at the end of loop we want to ask user to enter if he wants to again enter some values as you will see from the code itself.
If the answer is 'y' then he can "write" again but the problem is we are using getline and we have the problem with the first getline in this loop. The program does not recognise it after the first time use.
Here is the code:
int main() {
ofstream datoteka("podaci.txt", ios::app);
if (datoteka.fail()) {
cout << "Ne postojeca datoteka";
exit(1);
}
string ime;
string prezime;
char pol;
int godiste;
float prosjek;
char odluka;
do{
system("CLS");
cout << "Unesite ime: ";
getline(cin, ime);
datoteka << ime;
cout << "Unesite prezime: ";
getline(cin, prezime);
datoteka << " " << prezime;
cout << "Unesite pol(M - musko, Z - zensko): ";
cin >> pol;
datoteka << " " << pol;
cout << "Unesite godiste: ";
cin >> godiste;
datoteka << " " << godiste;
cout << "Unesite prosjek: ";
cin >> prosjek;
datoteka << " " << prosjek << endl;
cout << endl;
cout << "Da li zelite unijeti podatke za jos jednu osobu?" << endl;
cout << "[Y] za da, [N] za ne : ";
cin >> odluka;
} while (odluka != 'N' || odluka !='n');
The problem is with the
getline(cin,ime);
It wont recognize it after the first time use.
Can someone help me?
The basic problem is that this code mixes two different forms of input. Stream extractors (operator>>) do formatted input; they skip whitespace, then try to interpret non-whitespace characters, and stop when they encounter something that doesn't fit with what they're looking for. That works fine when you have multiple extractors: std::cin >> x >> y >> z;,
getline() is an unformatted input function; it grabs whatever is in the input stream, up to the first newline.
If you mix them you can get into trouble. The usual way to get around this is to call some variation of cin.ignore() when you switch from formatted to unformatted input, and that's where the code in the question goes astray.
At the end of the loop, the code calls std::cin >> odluka;. That reads one character from the console, and leaves any additional input in place. Since the console itself typically will sit waiting for characters until it sees a newline character, typing that single character also requires hitting the Enter key, which puts a newline into the input stream. The extractor leaves the newline there. When the loop repeats, the code calls std::getline(std::cin, ime), which sees the newline character and stops reading input.
So whenever you transition from formatted input to unformatted input you have to clear out any remnants from the previous input efforts.
Or you can always read a line at a time, and parse the input yourself.
i'm not sure exactly what the problem is. i took your code and it does what it's supposed to be doing on my machine (made a few adjustments so i can understand what's going on):
#include <iostream>
#include <vector>
#include <string>
#include <fstream>
using namespace::std;
int main() {
ofstream datoteka("podaci.txt", ios::app);
if (datoteka.fail()) {
cout << "Ne postojeca datoteka";
exit(1);
}
string ime;
string prezime;
char pol;
int godiste;
float prosjek;
// changed it to a char pointer
char odluka[] = { "Y" };
do{
system("CLS");
cout << "1: ";
getline(cin, ime);
datoteka << ime;
cout << "2: ";
getline(cin, prezime);
datoteka << " " << prezime;
cout << "3: ";
cin >> pol;
datoteka << " " << pol;
cout << "4: ";
cin >> godiste;
datoteka << " " << godiste;
cout << "5: ";
cin >> prosjek;
datoteka << " " << prosjek << endl;
cout << endl;
cout << "6" << endl;
cout << "[Y], [N]: ";
cin >> odluka;
// added this. it was not waiting for my input properly.
cin.get();
// print results
system("cls");
printf("results (press any key to move on)\n\n1: %s\n2: %s\n3: %c\n4: %d\n5: %.02f\n6: %c\n\n", ime.c_str(), prezime.c_str(), pol, godiste, prosjek, odluka);
getchar();
} while (_stricmp(odluka, "n")); // while "odluka" is not "n" or "N" (the _stricmp is not case-sensitive so they both return the same result)
system("cls");
printf("press any key to exit!\n");
getchar();
getchar();
}
here is the output from "podaci.txt":
test1 test1 1 1 1.1
test2 test2 2 2 2.2
consider using scanf/sprintf/printf with c strings in the future if this keeps malfunctioning perhaps?

c++ Program skips through lines while taking input [console application]

I am writing a sequential program on Library Management System which consists of two structs (books and student) and several functions.
Everything works accordingly except when I try to take console input in the function add_new_book() for the struct book , it skips line while taking input. I did research previously and then used the function cin.ignore() . That function works for the first two string inputs but after taking first two inputs, it skips the remaining input lines and terminates the function.
Here below is code from struct book and function add_new_book()
struct books{
int book_id;
string book_name;
string author_name;
string subject;
int fine;
};
void add_new_book(){
struct books b;
cout << "Enter the Book Name : ";
getline(cin, b.book_name);
cin.ignore();
//cin >> b.book_name;
cout << "Enter Author's Name : ";
getline(cin, b.author_name);
cin.ignore();
cout << "Enter Book id : ";
cin >> b.book_id;
cout << "Enter Book Cost : ";
cin >> b.fine;
cin.ignore();
cout << "Enter the Subject : ";
getline(cin, b.subject);
cout << "\n",b.book_name,b.author_name,b.book_id,b.fine,b.subject;
cout << "\n\n\t\t SUCCUSSFULLY ADDED \n";
// open a file in write mode.
ofstream outfile;
outfile.open("book1.txt");
outfile << b.book_name << endl;
outfile.close();
admin();
}
I suggest to get rid of cin.ignore's and use getline for numeric fields as well, using a std::string as a temporary buffer:
string s;
cout << "Enter Book id : ";
//cin >> b.book_id;
getline(cin, s);
Once you have the user input in a string, check its value and eventually assign it to the struct field, e.g. the book id has to be converted to int, this way:
b.book_id = std::atoi(s.c_str());
atoi will return zero if no conversion can be performed
if(b.book_id == 0)
{
cout << "Invalid book id";
}
Also, cout is not meant to be used the way you do. I would try something clean and tidy, like this:
cout << "Title : " << b.book_name << endl;
cout << "Author: " << b.author_name << endl;
//etc ...
You you shouldn't call std::cin.ignore() after std::getline(). getline will extract the '\n' from the input stream at the end of the line. Calling ignore will extract and discard another line.

String getline(cin,variable) function is skipping some lines of code

My program skips some code when I use the getline(cin,variablehere) function. I don't know whats wrong with the code. See the output below
#include <iostream>
#include <string>
using namespace std;
int main()
{
string getfirstname;
string lastname;
string address;
int contactnumber;
cout << "Enter First name : ";
getline(cin, getfirstname);
cin.ignore();
cout << "Enter Last name : ";
getline(cin, lastname);
cin.ignore();
cout << "Enter Address : ";
getline(cin, address);
cin.ignore();
cout << "Enter Contact number : ";
cin >> contactnumber;
cin.ignore();
CurrentNumberOfContacts += 1;
cout << "Successfully added to contact list!" << endl << endl;
cout << "Would you like to add another contact ? [Y/N] ";
cin >> response;
//more lines of codes below
return 0;
}
I have inputed 'int' as data type because it will contain numbers only
I recommend removing all the cin.ignore() commands.
One of the problems with user input is that the >> operator does not take the RETURN character out of the stream so if you follow it with a getline() the getline() will read the RETURN character instead of what you want to type in.
So I would change all your getline() to this:
// cin >> ws will skip any RETURN characters
// that may be left in the stream
getline(cin >> ws, lastname);
Also remove all of your cin.ignore() commands. They are not doing anything useful when used after a getline() command and if you change your getline() commands as I showed they should not be necessary at all.
So this should work:
int main()
{
string getfirstname;
string lastname;
string address;
char response;
int contactnumber;
int CurrentNumberOfContacts = 0;
cout << "Enter First name : ";
getline(cin >> ws, getfirstname);
cout << "Enter Last name : ";
getline(cin >> ws, lastname);
cout << "Enter Address : ";
getline(cin >> ws, address);
cout << "Enter Contact number : ";
cin >> contactnumber;
CurrentNumberOfContacts += 1;
cout << "Successfully added to contact list!" << endl << endl;
cout << "Would you like to add another contact ? [Y/N] ";
cin >> response;
//more lines of codes below
return 0;
}
Strictly speaking not all of your getline() functions need to employ the cin >> ws trick. I suppose the (incomplete) rules are as follows:
If you use a std::getline() after a >> then use:
std::getline(cin >> ws, line);
Otherwise just use:
std::getline(cin, line);
cin >> and getline do not cooperate very well. They have different strategies for how to deal with whitespace. getline removes the newline character, but cin >> leaves it. This means that after you use cin >> to read something, there will be a newline character left waiting in the input stream for the next getline to "use". Which means it will read an empty line into the string.
2 things. First, you don't really need cin.ignore() in this case as your using
getline().
before
cin >> variable
Second, I don't know why your program doesn't run, but I would suggest using a
getline()
call and see if that works. But I see no reason why your code is not working.
The answer provided by #Galic is quite good but If you want to read a line of characters without discarding the leading spaces you need another solution.
You could do:
char a='\n';
while (a=='\n')
{
cin.get(a);
}
cin.unget();
before doing your first getline. This assumes no trailing space resulting from a previous cin and that your first input line is not empty.

Program not waiting for cin

int x=0;
string fullname = "";
float salary;
float payincrease;
float newsal;
float monthlysal;
float retroactive;
while(x<3){
cout << "\n What is your full name?";
cin >> fullname;
cout << "\n What is your current salary? \t";
cin >> salary;
cout << "\n What is your pay increase? \t";
cin >> payincrease;
newsal = (salary*payincrease)+salary;
monthlysal = newsal/12.00;
retroactive = (monthlysal*6)-(salary/2);
cout << "\n" << fullname << "'s SALARY INFORMATION";
cout << "\n New Salary \t Monthly Salary \t Retroactive Pay";
cout << "\n \t" << newsal << "\t" << monthlysal << "\t" << retroactive;
x++;
}
My loop doesn't seem to stop for every time cin is asked, and instead instantly executes the loop 3 times on its own. How do I get it to stop when input is asked?
If the input stream isn't empty when you call cin, then cin uses the data already in the buffer instead of waiting for more from the user. You're using the extraction operator, so when cin is sending values to your variables, it skips leading whitespace in the buffer and stops on the next whitespace.
Put a breakpoint on this line:
cout << "\n What is your current salary? \t";
Run the program, and enter Bob Smith. When you hit the break point, hover your cursor over your string fullname. You'll see it stores only "Bob" not "Bob Smith". "Bob Smith" got put into the buffer, but when you use cin with the extraction operator, it skips any leading whitespace, puts the next value it finds into your variable, then stops on the next whitespace. To demonstrate this, try running this:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string str1,str2;
cin >> str1;
cin >> str2;
cout << str1 << " " << str2 << "\n\n";
return 0;
}
If you type in "Bob Smith", it will take your input only one time, even though you call cin twice. However, you'll see that both "Bob" and "Smith" got captured in the strings str1 and str2.
Therefore, you can conclude that cin stops populating your string fullname when it gets to the space between Bob and Smith. On your next call to cin, the buffer still contains "Smith", so instead of taking more input from the user, it attempts to fill your variable salary with "Smith". Obviously this isn't want you want to do. You can call flush and ignore on cin to wipe out the buffer before every time you use cin, or instead you could fix your logic and use getline to take in the full name, including spaces.
To fix your problem, all you need to do is use getline instead of cin >>, so replace this line:
cin >> fullname;
with this:
getline(cin,fullname,'\n');
Secondly, you're using a while loop to execute a set of actions a specific number of times. That's typically something you'd use a for loop for.
As an aside, you could also write tiny input validation loops that can help you debug or otherwise avoid attempting to put invalid input into your variables (such as "Smith" into a float). Something like this could work:
for(;;)
{
if(cin >> salary)
break;
cin.clear();
cin.ignore(INT_MAX,'\n');
}
Note that cin returns a value, so you can use it in an if statement. If it gets valid input, it will return true. If not, it will return false. To make it more explicit, you could also just use a normal call to cin without the if statement, and then check if cin.good(), which amounts to basically the same net effect. If you're not using Visual Studio and get an error about INT_MAX, you might need to #include limits.h to resolve it.
That occurs if you input a char where an int is expected.
Use cin.clear(); and cin.ignore(numeric_limits<streamsize>::max(), '\n'); to limit an input to int's only.
Other than that, it won't skip if the correct data type is put in.
#include <string>
#include <iostream>
#include <limits>
using namespace std ;
int main(void)
{
int x=0;
string fullname = "";
float salary;
float payincrease;
float newsal;
float monthlysal;
float retroactive;
while(x<3)
{
cout << "\n What is your full name?";
cin >> fullname;
cin.ignore( 1000, '\n' );
cout << "\n What is your current salary? \t";
cin >> salary;
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout << "\n What is your pay increase? \t";
cin >> payincrease;
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
newsal = (salary*payincrease)+salary;
monthlysal = newsal/12.00;
retroactive = (monthlysal*6)-(salary/2);
cout << "\n" << fullname << "'s SALARY INFORMATION";
cout << "\n New Salary \t Monthly Salary \t Retroactive Pay";
cout << "\n \t" << newsal << "\t" << monthlysal << "\t" << retroactive;
x++;
}
cout<<" \nPress any key to continue\n";
cin.ignore();
cin.get();
return 0;
}
Check your variable types, I noticed mine accepting a digit instead of a character, had the same problem (not stopping, loop just kept going on).
> std::cin >> this->controls.button
> DETOX_NUMBER button; // (int)
Change to:
> char button;

c++ cin input not working?

#include <iostream>
#include <string>
struct Car{
std::string model;
unsigned int year;
};
int main(){
using namespace std;
int carNum;
cout << "How many cars do you wish you catalog? ";
cin >> carNum;
Car * cars = new Car[carNum];
for (int i=0;i<carNum;i++){
cout << "Car #" << i << endl;
cout << "Please enter the make: ";
getline(cin, cars[i].model);
cout << "Please enter the year made: ";
cars[i].year = cin.get();
}
cout << "Here's your collection" << endl;
for (int i=0;i<carNum;i++){
cout << cars[i].model << " " << cars[i].year << endl;
}
delete [] cars;
return 0;
}
When i execute the program, the getline(cin, car[i].model) just get skipped over. Why is this?
like this:
Car #2
Please enter the make: Please enter the year made:
Simple reason.
When you do cin >> whatever, a \n is left behind (it was added when you pressed Enter). By default, getline reads until the next \n, so the next read will simply read an empty string.
The solution is to discard that \n. You can do it by putting this:
cin.ignore(numeric_limits<streamsize>::max(),'\n');
Just after the cin >> carNum.
Don't forget to include limits in order to use numeric_limits.
After every cin call using insertion operator. You must call cin.ignore() if you want cin.getline () to work.
As cin>> leaves behind a '\n' character when you press enter and because of that when you use getline () it picks up the \n
and takes no input as it finds \n in the input stream which is the default delimiter.
So you can either do cin.ignore () after every cin>> or simply set a delimiter character cin.getline ()