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?
Related
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.
I want to read strings with white spaces into members of a structure. Tried using getline but both the output statements are clubbed with a single cin for both. As per the similar posts here, tried using cin.ignore, but the input is not read into the member of the structure. Pls help. It's a part of my assignment and I'm a beginner in C++. This is how my code looks like:
#include <string.h>
using namespace std;
struct book {
string title, author;
int no_of_pages, year;
float price;
};
int main() {
int N;
cout << "Enter the no. of books whose details are to be entered:" << endl;
cin >> N;
book b[N];
int x;
for (x = 0; x < N; x++) {
cout << "Enter the title of book #" << x + 1 << ":" << endl;
getline(cin, (b[x].title));
// cin.ignore();
cin.ignore(1000, '\n');
cout << "Enter the author's name:" << endl;
getline(cin, (b[x].author));
cout << "Enter the no. of pages:" << endl;
cin >> b[x].no_of_pages;
cout << "Enter the price of book:" << endl;
cin >> b[x].price;
cout << "Enter the year of publishing" << endl;
cin >> b[x].year;
}
for (x = 0; x < N; x++) {
cout << "\n\n";
cout << "The details of book" << x + 1 << " are:" << endl;
cout << "Title :" << b[x].title << endl;
cout << "Author :" << b[x].author << endl;
cout << "No. of pages :" << b[x].no_of_pages << endl;
cout << "Price :" << b[x].price << endl;
cout << "Publishing year:" << b[x].year << endl;
cout << "---------------------------------------------";
}
return 0;
}
There's no point in using cin.ignore() in between two calls to getline. ignore is used to discard remaining characters after numeric input. So the place to use it is after numeric input and before the next getline. Like this
cout << "Enter the title of book #" << x + 1 << ":" << endl;
getline(cin, (b[x].title));
cout << "Enter the author's name:" << endl;
getline(cin, (b[x].author));
cout << "Enter the no. of pages:" << endl;
cin >> b[x].no_of_pages;
cout << "Enter the price of book:" << endl;
cin >> b[x].price;
cout << "Enter the year of publishing" << endl;
cin >> b[x].year;
cin.ignore(1000, '\n');
That said I would just read everything using getline, then convert the strings to numbers where needed. That's simpler and cleaner, all you need to know is how to convert a string to an integer, which you can easily research for yourself.
There are two places you should put cin.ignore in your code:
cout << "Enter the no. of books whose details are to be entered:" << endl;
cin >> N;
// First cin.ignore here
cin.ignore(1000, '\n');
cout << "Enter the year of publishing" << endl;
cin >> b[x].year;
// Second cin.ignore here
cin.ignore(1000, '\n');
Besides this I see two more problems in your code:
#include <string> not <string.h>
add #include <iostream>
Why cin.ignore is necessary? User is expected to provide new line ('\n') delimited input. When getline is used, it leaves the input stream in such a state that the next attempt to read input from stream will start at next line. This is not true for operator >>. What int x; cin >> x; does here is it reads only the integer not the new line character present right after the integer. Hence, the next attempt to read will continue within the same line. getline will then find no character before new line and hence will fetch an empty string. To avoid this and to effectively start reading from the next line, cin.ignore is necessary.
I wrote this code. It works in the main function
cout << "Enter the patron's name: ";
getline(std::cin, patron.name);
cout << "Enter the book title: ";
getline(std::cin, book.title);
cout << book.title << " is now checked out to " << patron.name << endl;
However, when I put it under a do while loop with switch case, it does not work anymore.
do {
cout << endl << "? "; cin >> choice;
switch (toupper(choice)){
case 'T':
cout << "Enter the patron's name: ";
getline(std::cin, patron.name);
cout << "Enter the book title: ";
getline(std::cin, book.title);
cout << book.title << " is now checked out to " << patron.name << endl;
break;
}[enter image description here][1]
} while (choice != 'Q' && choice!= 'q');
The input was like:
Could anyone explain to me why this happened? Thanks
After this statement
cout << endl << "? "; cin >> choice;
insert
std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );
to remove the new line character (that corresponds to the pressed Enter key after the input) that is still in the input buffer, Otherwise a call of getline will read an empty string.
You should include the header <limits> to use the class numeric_limits
This \n after T(your input) is being consumed by getline. That's why you are getting such behaviour. You need to flush the newline out of the buffer.
You can do this by adding this statement as shown.
std::cin.ignore (std::numeric_limits<std::streamsize>::max(), '\n');
cout << "Enter the patron's name: ";
In the below code, I'm running into an error when I try to get the user to input their name. My program just skips it over and goes right over to making the function calls without allowing the user to enter their name. Despite the error, my program is compiling. I'm not sure what's going wrong as I wrote that part based off other examples I found on here. Any suggestions?
#include <iostream>
#include <string>
#include <time.h>
using namespace std;
char showMenu();
void getLottoPicks(int[]);
void genWinNums(int[]);
bool noDuplicates(int[]);
const int SIZE = 7;
int main()
{
int userTicket[SIZE] = {0};
int winningNums[SIZE] = {0};
char choice;
string name;
srand(time(NULL));
do
{
choice = showMenu();
if (choice == '1')
{
cout << "Please enter your name: " << endl;
getline(cin, name);
getLottoPicks(userTicket);
genWinNums(winningNums);
for (int i = 0; i < SIZE; i++)
cout << winningNums[i];
}
} while (choice != 'Q' && choice != 'q');
system("PAUSE");
return 0;
}
Added the code for showMenu:
char showMenu()
{
char choice;
cout << "LITTLETON CITY LOTTO MODEL:" << endl;
cout << "---------------------------" << endl;
cout << "1) Play Lotto" << endl;
cout << "Q) Quit Program" << endl;
cout << "Please make a selection: " << endl;
cin >> choice;
return choice;
}
And getLottoPicks (this part is very wrong and I'm still working on it):
void getLottoPicks(int numbers[])
{
cout << "Please enter your 7 lotto number picks between 1 and 40: " << endl;
for (int i = 0; i < SIZE; i++)
{
cout << "Selection #" << i + 1 << endl;
cin >> numbers[i];
if (numbers[i] < 1 || numbers[i] > 40)
{
cout << "Please choose a number between 1 and 40: " << endl;
cin >> numbers[i];
}
if (noDuplicates(numbers) == false)
{
do
{
cout << "You already picked this number. Please enter a different number: " << endl;
cin >> numbers[i];
noDuplicates(numbers);
} while (noDuplicates(numbers) == false);
}
}
}
After doing cin >> choice; inside char showMenu(), if a user inputs 1[ENTER], the char consumes 1 character from cin, and the newline stays inside the stream. Then, when the program gets to getline(cin, name);, it notices that there's still something inside cin, and reads it. It's a newline character, so getline gets it and returns. That's why the program is behaving the way it is.
In order to fix it - add cin.ignore(); inside char showMenu(), right after you read the input. cin.ignore() ignores the next character - in our case, the newline char.
And a word of advice - try not to mix getline with operator >>. They work in a slightly different way, and can get you into trouble! Or, at least remember to always ignore() after you get anything from std::cin. It may save you a lot of work.
This fixes the code:
char showMenu()
{
char choice;
cout << "LITTLETON CITY LOTTO MODEL:" << endl;
cout << "---------------------------" << endl;
cout << "1) Play Lotto" << endl;
cout << "Q) Quit Program" << endl;
cout << "Please make a selection: " << endl;
cin >> choice;
cin.ignore();
return choice;
}
from looking at code showMenu function has problem. and it's not returning asccii equivalent of '1' that is: 31 integer. try printing value returned by showmenu. you will get that
UPDATE:
It is because cin in delimited by ' '(whitespace) and getline by '\n' character, so when enter name and press enter cin in showmenu will consume whole string except '\n' from istream and that is read by getline. to see this when it ask for choice enter string like 1 myname (1 whitespace myname)and press ENTER will display name. now cin will read 1 in choice and myname in name by getline.
I am so lost. I am having an issue with the following code when saving and loading data to a binary file. I have a very similar/exact piece of code that works with a different object. I think it has something to do with the email address and the # symbol in it. Here are the important functions.
/* This is my save to file function */
FILE *file=fopen("patronsave","wb");
fwrite(&buffer,sizeof(buffer),1,file);
for(int i=0;i<3;i++){
Patron_Class *ppointer = new Patron_Class();
cout << "\n" << endl;
ppointer->save(file);
}
fclose(file);
That is the function I use to save my objects to a file.
Here is my code that I am using to load the file:
vector<Patron_Class*> Patron_Entries;
FILE *file=fopen("patronsave","rb");
fread(&buffer,sizeof(buffer),1,file);
printf("Buffer: %d\n",buffer);
for(int i=0;i<buffer;i++){
Patron_Class *pointer2 =new Patron_Class(file);
Patron_Entries.push_back(pointer2);
Patron_Entries[i] -> print();
system("pause");
}
fclose(file);
If I run the save function and then immediatly run the load function it works, but if I only run the load function it crashes when it tried to load the email. Here is my class and object code:
class Patron_Class{
public:
long patron_id;
string F_name;
string L_name;
long phone_num;
string email;
string street_address;
string city;
string state;
int zip_code;
Patron_Class(){
cout << "Please enter a new ID" << endl;
cin >> patron_id;
cin.ignore(1000, '\n');
system("cls");
cout << "Please enter a First name" << endl;
cin >> F_name;
cin.ignore(1000, '\n');
system("cls");
cout << "Please enter a last name" << endl;
cin >> L_name;
cin.ignore(1000, '\n');
system("cls");
cout << "Please enter a phone number" << endl;
cin >> phone_num;
cin.ignore(1000, '\n');
system("cls");
cout << "Please enter a email" << endl;
cin >> email;
cin.ignore(1000, '\n');
system("cls");
cout << "Please enter a street address" << endl;
cin >> street_address;
cin.ignore(1000, '\n');
system("cls");
cout << "Please enter a city" << endl;
cin >> city;
cin.ignore(1000, '\n');
system("cls");
cout << "Please enter a State via it's initials" << endl;
cin >> state;
cin.ignore(1000, '\n');
system("cls");
cout << "Please enter a zip code" << endl;
cin >> zip_code;
cin.ignore(1000, '\n');
system("cls");
cout << "You have created a new patron named: " << F_name << " " << L_name << endl;
}
Patron_Class(FILE *inputfile){
fread(&patron_id, sizeof(patron_id),1,inputfile);
fread(&F_name, sizeof(F_name),1,inputfile);
fread(&L_name, sizeof(L_name),1,inputfile);
fread(&phone_num, sizeof(phone_num),1,inputfile);
fread(&email, sizeof(email),1,inputfile);
fread(&street_address, sizeof(street_address),1,inputfile);
fread(&city, sizeof(city),1,inputfile);
fread(&state, sizeof(state),1,inputfile);
fread(&zip_code, sizeof(zip_code),1,inputfile);
}
void print(){
cout << patron_id << " " << F_name << " " << L_name << " " << phone_num << " " << email << " " << street_address << " " << city << " " << state << " " << zip_code << "\n" << endl;
}
void save(FILE *inputFile){
fwrite(&patron_id, sizeof(patron_id),1,inputFile);
fwrite(&F_name, sizeof(F_name),1,inputFile);
fwrite(&L_name, sizeof(L_name),1,inputFile);
fwrite(&phone_num, sizeof(phone_num),1,inputFile);
fwrite(&email, sizeof(email),1,inputFile);
fwrite(&street_address, sizeof(street_address),1,inputFile);
fwrite(&city, sizeof(city),1,inputFile);
fwrite(&state, sizeof(state),1,inputFile);
fwrite(&zip_code, sizeof(zip_code),1,inputFile);
}
};
Does anyone know why it might be crashing?
This is CLEARLY wrong:
string F_name;
...
fread(&F_name, sizeof(F_name),1,inputfile);
...
fwrite(&F_name, sizeof(F_name),1,inputFile);
[The same applies to all the other strings in your PatronClass - I'm using the first one for this example]
The class std::string will look something like this (for illustration purposes, the exact implementation involves several layers, some templates, and other stuff, so this is simplified for the purposes of the explanation to follow):
class string
{
char *str;
int len;
public:
...
};
So, when you do fread from the file and fwrite to the file, you are reading/writing the char *str; and int len; members from/to the file.
Let's say we start your program from scratch, with no data in the file, and we use the Patron_Class() constructor. So we read in an id, and then the F_name from the console. Let's say we enter Charles. So somehow the string class will allocate 8 bytes of memory, at the address of 0x600018. So string::str == 0x600018 and len = 8 - at location 6000018 in the heap are the letters C h a r l e s \0 [ spaces just to illustrate they are in separate memory locations]. Now we save this to a file. So the file contains 00600018 00000008. Now we stop the program and start it again, using the PatronClass(file) constructor. The heap is completely empty. We load the file data, so string::str = 0x600018 and len = 8, but that locaton 0x600018 does not contain C h a r l e s \0, but whatever the heap normally is filed with when the heap is initialized [quite likely 0]. So no wonder your name doesn't appear.
Now, the exact behaviour of your actual program is probably not the same as what I've described above, but it will NOT work right. No way, never, ever. No matter what characters you have or haven't got in names, email addresses or any other string in your code. The only reason it may APPEAR to work is that the data is still, for the most part, there in the heap, and it seems to be working because it doesn't get overwritten by something else in your case.