Im having issues displaying the output. There is always and extra line being printed. I did some research and it turns out that its because my getline. Also I apologize for the format
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
struct menuItemType
{
string menuItem;
double menuPrice;
};
int main()
{
menuItemType plainEgg;
menuItemType baconEgg;
menuItemType muffin;
menuItemType frenchToast;
menuItemType fruitBasket;
menuItemType cereal;
menuItemType coffee;
menuItemType tea;
ifstream infile;
infile.open("Ch9_Ex5Data.txt");
while(infile)
{
getline(infile,plainEgg.menuItem);
infile >> plainEgg.menuPrice;
getline(infile,baconEgg.menuItem);
infile >> baconEgg.menuPrice;
getline(infile,muffin.menuItem);
infile >> muffin.menuPrice;
getline(infile,frenchToast.menuItem);
infile >> frenchToast.menuPrice;
getline(infile,fruitBasket.menuItem);
infile >> fruitBasket.menuPrice;
getline(infile,cereal.menuItem);
infile >> cereal.menuPrice;
getline(infile,coffee.menuItem);
infile >> coffee.menuPrice;
getline(infile,tea.menuItem);
infile >> tea.menuPrice;
cout << plainEgg.menuItem << plainEgg.menuPrice << endl;
cout << baconEgg.menuItem << baconEgg.menuPrice << endl;
cout << muffin.menuItem << muffin.menuPrice << endl;
cout << frenchToast.menuItem << frenchToast.menuPrice << endl;
cout << fruitBasket.menuItem << fruitBasket.menuPrice << endl;
cout << cereal.menuItem << cereal.menuPrice << endl;
cout << coffee.menuItem << coffee.menuPrice << endl;
cout << tea.menuItem << tea.menuPrice << endl;
}
infile.close();
return 0;
}
Contents in the file
Plain Eggs
1.45
Bacon and Eggs
2.45
etc.
I tried using
if (infile.eof())
cout << endl;
this is my output
Plain Egg1.45 // <-- this is the only correct output
Bacon
and Egg2.45
Muffin
0.99
French
Toast1.99
Fruit
Basket2.49
Cereal
0.69
Coffee
0.50
Tea
0.75
Only thing that printed correctly was the very first line. (Note)I have to use structure.
There are at least three major problems in the shown code. The first one is not properly checking for an end of file condition:
while(infile)
This checks if the input stream already entered a failed state.
After reading the last line in your file, your input stream hasn't failed yet. Everything, up until point, has went exactly according to plan.
So, after the last line in the file, this condition will still evaluate to true, running the loop one more time. Of course, it will fail miserably.
And explicitly checking if (infile.eof()) will, again, if the file has already encountered an end-of-file condition.
What you probably want to do is to try to start reading the next line from the file, and if it fails, then you've reached the end of it:
while (getline(infile,plainEgg.menuItem))
{
// The code that reads the next set of items.
But this, alone, won't solve all of your problems.
getline(infile,plainEgg.menuItem);
infile >> plainEgg.menuPrice;
This is mixing an unformatted input operation, std::getline(), with a formatted input operation, the >> operator.
Such combination is fragile, and has several non-obvious failure modes, as explained here, so I won't repeat that; just see this earlier question for more information.
Although there are ways to do this correctly, it's going to be easier for you to rewrite your code to use only std::getline(), or the >> operator to read everything, until you fully understand how to correctly combine unformatted and formatted input operations.
The last problem is a minor quibble. The shown code fails to properly handle incomplete input, and error checking. As shown, as long as it successfully reads the first piece in a set of data, it assumes that the remaining data will be there. You should verify that every input operation (whether you choose to use formatted or unformatted input operations) is properly checked for success.
Related
I am trying to read in an essay from a file which I then need to change each beginning letter of a sentence to an upper case letter and then send the corrected essay back to a file called correct.txt. The essay is stored in essay.txt.
So far I am just working with understanding the conversions from files to string in order for me to proceed with the rest of the question. So far, I have a string variable which which holds the essay with the words separated by a single space. I noticed that when I was trying to work with the size of my new string, it was not giving me the correct answer and I cannot figure out why. If you have any suggestions on how I can get it to notice the correct amount of characters, I would really appreciate it.
One more question while you're here, I know that moving forward, in order to change the beginning letters of the sentence to upper case, I need to first find the periods. Once I have this position, I can use pos+2 (including the preceding whitespace after the period) for the character that needs to become upper case. Is this the correct way of going about this and do you have any other tips on how to go forward with this?
Here is my code so far:
#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>
using namespace std;
int main(){
//declaring variables and creating objects
ifstream inputFile;
ofstream outputFile;
char inputFileName[20], outFileName[20];
cout << "Enter name of the file you want to open: " << endl;
cin >> inputFileName;
inputFile.open(inputFileName);
if (inputFile.fail()) {
cout << "Input file opening failed.\n";
exit(1);
}
cout << "Enter name of the file you want to send the output to: " << endl;
cin >> outFileName;
outputFile.open(outFileName);
if (outputFile.fail()) {
cout << "Output file opening failed.\n";
exit(1);
}
//while the file is open, it sends the contents to the string variable "essay"
string essay;
inputFile >> essay;
while (!inputFile.eof()) {
cout << essay << " ";
inputFile >> essay;
}
//this is to check for the correct size of the string "essay" before moving on to the rest of the code
int size = essay.size();
cout << size << endl;
return 0;
}
Your understanding of how the input stream works is incorrect.
The core of your code is this loop:
string essay;
inputFile >> essay;
while (!inputFile.eof()) {
cout << essay << " ";
inputFile >> essay;
}
What this does is that it reads the first word into essay, then, as long as the eof marker is not set on the stream it echoes back the word just read, and then reads another word, overwriting the previous one.
Here's the correct code. Note that checking for eof in a loop condition is a bad idea, because it doesn't quite do what you want, and would also get you stuck in an infinite loop if the stream instead entered an error condition.
string word;
while (inputFile >> word) { // read a word and stop if this fails for any reason
essay += word;
essay += " ";
}
Though I'm not sure why you read the file word by word instead of all at once.
Also, I feel the need to repeat what M.M. said in a comment: your use of raw character arrays on input is unsafe and unnecessary. Just use string. You need to then write inputFile.open(inputFileName.c_str()) unless your standard library is new enough to have the string overloads of these functions, but that is fine. The other way of doing it is dangerous and a very bad habit to get into.
Try include cstring on top of string as well.
String is considered char array which is a more 'unique' way of storing data. You can try the code listed below.
int size = essay.length();
I was going through a code in my school textbook, wherein there is a line who's function is to clear the input buffer (mentioned as a comment in the code).
I couldn't quite understand its purpose. It is definitely required as its removal messes up the console input process.
Please explain what its function is, and what is happening when I remove it.
I have also tried using cin.ignore(); and it works just fine too. How is the function used here, is it an exact replacement of cin.ignore()?
P.S. In school we are using the older version of C++. Hence the ".h" extension, clrscr();, etc.
#include <iostream.h>
#include <fstream.h>
#include <conio.h>
void main(){
clrscr();
ofstream fout("student.txt", ios::out);
char name[30], ch;
float marks = 0.0;
for(int i = 0; i < 5; i++){
cout << "Student " << (i+1) << ":\tName: ";
cin.get(name,30);
cout << "\t\tMarks: ";
cin >> marks;
cin.get(ch); //for clearing input buffer (This thing!)
fout << name << '\n' << marks << '\n';
}
fout.close();
ifstream fin("student.txt", ios::in);
fin.seekg(0);
cout << "\n";
for(int i = 0; i < 5; i++){
fin.get(name,30);
fin.get(ch); //Again
fin >> marks;
fin.get(ch); //Same
cout << "Student Name: " << name;
cout << "\tMarks: " << marks << "\n";
}
fin.close();
getch();
}
cin >> marks;
cin.get(ch); //for clearing input buffer (This thing!)
This is a not-so-robust way of clearing the input buffer. If you type a number followed by Enter, the first line will consume the number and put the value in marks while the second line will read the newline character and discard it.
It is not robust since it does not account for spaces a user might have entered after the number. A more robust method would be to use istream::ignore.
cin >> marks;
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
I just want to start with pointing out that you are not using "the older version of C++". You are just using some c code (like clrscr()) and c styled programming, and indeed probably not cpp11 or cpp14. Also header files for C++ are often still just .h.
Now the answer to your question:
cin.get(ch);
The '\n' character gets read into ch. '\n' is one character, a newline character.
does indeed do the same thing as
cin.ignore();
It is used to clear the input buffer, which means that the empty end of line ('\n') is being deleted from the input buffer.
Why is this done you ask? This is a good example of why you would do that. Hope this helped you!
Im writing a program to practice with the language, but im getting some pretty weird output from code that seems right to me.
The code:
#include <iostream>
#include <fstream>
#include <list>
struct Car
{
std::string make;
std::string model;
int partNo;
double price;
int quantity;
std::string partname;
};
void AddItem();
void _Update(int PartNo, int quantity);
void UpdateList(std::list<Car>& _Car);
int main()
{
std::list<Car> _Car;
UpdateList(_Car);
for(std::list<Car>::iterator iter = _Car.begin(); iter != _Car.end(); iter++)
{
std::cout << iter->make << " " << iter->model << " " << iter->partNo << " " << iter->price << " " << iter->quantity << " " << iter->partname << std::endl;
}
}
void UpdateList(std::list<Car>& _Car)
{
std::ifstream File("CarParts.txt");
if(!File.is_open())
std::cerr << "Bad file input....... closing....";
while(!File.eof())
{
Car tempObj;
File >> tempObj.make >> tempObj.model >> tempObj.partNo >> tempObj.price >> tempObj.quantity;
getline(File,tempObj.partname);
_Car.push_back(tempObj);
}
File.close();
}
Outpost given:
Pajero NA1H25 1 3.65 11 BLADE W/S WIPER Honda_Sivic R34gFk 2 4.97 15
ENGINE CHANGE 2 4.97 15
Notepad file:
Pajero NA1H25 1 3.65 11 BLADE W/S WIPER
HondaSivic R34gFk 2 4.97 15 ENGINE CHANGE
what is with the three numbers under the two lines i actually wanted printed out? It's really confusing me... Thanks if you can help!
This is a common issue people run into while reading file data in C++. The issue is your usage of eof. That flag is only set after an attempt to read data has failed.
Because of that, after reading the first two lines, it still has not hit the end of the file. It has read right up to it, but eof has not been set. Then it will loop around a third time, attempt to read 2 lines, and then exit after that. The problem is that you never check for eof before pushing the results of that third loop into your car list.
In your case, you can either move your eof check to after the getline call, or make use of the getline return value.
For example:
while(true)
{
Car tempObj;
File >> tempObj.make >> tempObj.model >> tempObj.partNo
>> tempObj.price >> tempObj.quantity;
if (!getline(File,tempObj.partname)) break;
_Car.push_back(tempObj);
}
This will check whether the data was read successfully before pushing.
For starters, set the namespace of the program to std to avoid the nasty std::string etc syntax.
Near the top of your file, under your imports, insert:
using namespace std;
It looks like the objective is to populate a list from a file.
Looking at this part:
File >> tempObj.make >> tempObj.model >> tempObj.partNo >> tempObj.price >> tempObj.quantity;
getline(File,tempObj.partname);
I think a better solution would be to parse each line withgetLine, and then parse the data accordingly with a space delimeter or a comma. Whitespace delimiters can be finiky.
Why does this program run fine?
#include<iostream>
using namespace std;
int main()
{
cout <<"What year was your house built?\n";
int year;
cin >> year;
cout << "What is its street address?\n";
char address[80];
cin>>address;
cout << "Year built: " << year << endl;
cout << "Address: " << address << endl;
cout << "Done!\n";
return 0;
}
And why does this program not give the chance to enter the address?
#include <iostream>
int main()
{
using namespace std;
cout <<"What year was your house built?\n";
int year;
cin >> year;
cout << "What is its street address?\n";
char address[80];
cin.getline(address, 80);
cout << "Year built: " << year << endl;
cout << "Address: " << address << endl;
cout << "Done!\n";
return 0;
}
cin>> leaves the newline character (\n) in the iostream. If getline is used after cin>>, the getline sees this newline character as leading whitespace, thinks it is finished and stops reading any further.
Two ways to solve the problem:
Avoid putting getline after cin >>
OR
Consume the trailing newline character from the cin>> before calling getline, by "grabbing" it and putting it into a "dummy" variable.
string dummy;
getline(cin, dummy);
Why does the first program work & Second doesn't?
First Program:
The cin statement uses the entered year and leaves the \n in the stream as garbage. The cin statement does NOT read (or "grab") \n. The cin ignores \n when reading data. So cin in program 1 can read the data properly.
Second Program:
The getline, reads and grabs \n. So, when it sees the \n left out from cin, it grabs the \n and thinks it is finished reading, resulting in second program not working as you expected.
Sit down for a second. This is not easy to explain properly.
When your program gets to a point where it reads from std::cin, it does not just automatically wait for you to type something. std::cin is an input stream, the same as you use to read from a file on disk. The only reason it waits is if there is not enough data available yet to satisfy the read request.
Meanwhile, when you run your program from the console, the console window itself is also a program. It is interpreting your key presses and translating them into text, and feeding that text a line at a time to the standard input of your program (so that std::cin can see it). This is important and useful, because it allows the backspace key to work the way you expect it to.
So if your program is supposed to read a number, and you type a number, your program will not see the number until you hit return to complete the line. However, the newline character is still sitting in the input stream, because you didn't read it yet. The operator>> skips whitespace before the value that it's trying to read, but it leaves behind any whitespace after the value.
Now, if the next reading operation is another call to operator>>, then it does the same thing again and it works fine: the newline that we didn't read before is whitespace, so it gets skipped, and then the next thing gets read.
However, the getline() function reads from the current point until the next newline. It never skips any leading or trailing whitespace, and an empty line is considered completely valid. So if you typed a number and hit return, then the getline() call will see the newline and finish reading right away, because it already has an end of the line. The program does not stop because there was already enough data available to finish the operation.
To fix this, the safest, simplest and most robust way of dealing with the input is to always read the entire line first, and then re-interpret the contents of the line. To make this easier, we will use the std::string class to represent strings. We can read into the string instance with std::getline (notice: a global function, not a member function of cin), and create a std::stringstream instance from that string.
The idea is: the program will always wait at an input request, because the previous request always read the newline character (because we read the entire line). So that makes the control flow work the way we expected it to. The std::stringstream instance can be treated like a file or standard input: it's just another stream, except it takes its data from the string. So we can get numbers out of it with operator>>, and so on.
The other benefit of this comes when the user inputs invalid data. It can be quite hard to recover from this properly, if you are just reading directly from std::cin. But if you are using the stringstream as a "buffer", then you can just throw it away and try again with a new line of input.
An example:
#include <iostream>
#include <string>
#include <sstream>
int main()
{
using namespace std;
string line;
int year;
while (true) {
cout << "What year was your house built?" << endl;
getline(cin, line);
stringstream input(line);
if (line >> year) { break; }
}
cout << "What is its street address?\n";
getline(cin, line);
cout << "Year built: " << year << endl;
cout << "Address: " << line << endl;
cout << "Done!\n";
}
Maybe you have a stray terminator in cin?|
Try cin.clear();
This question already has answers here:
Need help with getline() [duplicate]
(7 answers)
Closed 7 years ago.
This is probably a very simple problem but forgive me as I am new.
Here is my code:
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
int main ()
{
string name;
int i;
string mystr;
float price = 0;
cout << "Hello World!" << endl;
cout << "What is your name? ";
cin >> name;
cout << "Hello " << name << endl;
cout << "How old are you? ";
cin >> i;
cout << "Wow " << i << endl;
cout << "How much is that jacket? ";
getline (cin,mystr);
stringstream(mystr) >> price;
cout << price << endl;
system("pause");
return 0;
}
The problem is that when asked how much is that jacket? getline does not ask the user for input and just inputs the initial value of "0". Why is this?
You have to be careful when mixing operator>> with getline. The problem is, when you use operator>>, the user enters their data, then presses the enter key, which puts a newline character into the input buffer. Since operator>> is whitespace delimited, the newline character is not put into the variable, and it stays in the input buffer. Then, when you call getline, a newline character is the only thing it's looking for. Since that's the first thing in the buffer, it finds what it's looking for right away, and never needs to prompt the user.
Fix:
If you're going to call getline after you use operator>>, call ignore in between, or do something else to get rid of that newline character, perhaps a dummy call to getline.
Another option, and this is along the lines of what Martin was talking about, is to not use operator>> at all, and only use getline, then convert your strings to whatever datatype you need. This has a side effect of making your code more safe and robust. I would first write a function like this:
int getInt(std::istream & is)
{
std::string input;
std::getline(is,input);
// C++11 version
return stoi(input); // throws on failure
// C++98 version
/*
std::istringstream iss(input);
int i;
if (!(iss >> i)) {
// handle error somehow
}
return i;
*/
}
You can create a similar function for floats, doubles and other things. Then when you need in int, instead of this:
cin >> i;
You do this:
i = getInt(cin);
Its because you have a '\n' left lying on the input stream from a previous call.
cin >> i; // This reads the number but the '\n' you hit after the number
// is still on the input.
The easiest way to do interactive user input is to make sure each line is processed independently (as the user will hit enter after each prompt).
As a result always read a line, then process the line (until you get familiar with the streams).
std::string line;
std::getline(std::cin, line);
std::stringstream linestream(line);
// Now processes linestream.
std::string garbage;
lienstream >> i >> garbage; // You may want to check for garbage after the number.
if (!garbage.empty())
{
std::cout << "Error\n";
}
Ignore some characters until line feed is reached.
cin.ignore(256, '\n')
getline (cin,mystr);