I have the following structure:
struct productInfo
{
int item;
string details;
double cost;
};
I have a file that will input 10 different products that each contain an item, details, and cost. I have tried to input it using inFile.getline but it just doesn't work. Can anyone give me an example of how to do this? I would appreciate it.
Edit
The file contains 10 lines that look like this:
570314,SanDisk Sansa Clip 8 GB MP3 Player Black,55.99
Can you provide an example please.
Edit
Sorry guys, I am new to C++ and I don't really understand the suggestions. This is what I have tried.
void readFile(ifstream & inFile, productInfo products[])
{
inFile.ignore(LINE_LEN,'\n'); // The first line is not needed
for (int index = 0; index < 10; index++)
{
inFile.getline(products[index].item,SIZE,DELIMETER);
inFile.getline(products[index].details,SIZE,DELIMETER);
inFile.getline(products[index].cost,SIZE,DELIMETER);
}
}
This is another approach that uses fstream to read the file and getline() to read each line on the file. The parsing of the line itself was left out on purpose since other posts have already done that.
After each line is read and parsed into a productInfo, the application stores it on a vector, so all products could be accessed in memory.
#include <iostream>
#include <fstream>
#include <vector>
#include <iterator>
#include <string>
using namespace std;
struct productInfo
{
int item;
string details;
double cost;
};
int main()
{
vector<productInfo> product_list;
ifstream InFile("list.txt");
if (!InFile)
{
cerr << "CouldnĀ“t open input file" << endl;
return -1;
}
string line;
while (getline(InFile, line))
{ // from here on, check the post: How to parse complex string with C++ ?
// https://stackoverflow.com/questions/2073054/how-to-parse-complex-string-with-c
// to know how to break the string using comma ',' as a token
cout << line << endl;
// productInfo new_product;
// new_product.item =
// new_product.details =
// new_product.cost =
// product_list.push_back(new_product);
}
// Loop the list printing each item
// for (int i = 0; i < product_list.size(); i++)
// cout << "Item #" << i << " number:" << product_list[i].item <<
// " details:" << product_list[i].details <<
// " cost:" << product_list[i].cost << endl;
}
EDIT: I decided to take a shot at parsing the line and wrote the code below. Some C++ folks might not like the strtok() method of handling things but there it is.
string line;
while (getline(InFile, line))
{
if (line.empty())
break;
//cout << "***** Parsing: " << line << " *****" << endl;
productInfo new_product;
// My favorite parsing method: strtok()
char *tmp = strtok(const_cast<char*>(line.c_str()), ",");
stringstream ss_item(tmp);
ss_item >> new_product.item;
//cout << "item: " << tmp << endl;
//cout << "item: " << new_product.item << endl;
tmp = strtok(NULL, ",");
new_product.details += tmp;
//cout << "details: " << tmp << endl;
//cout << "details: " << new_product.details << endl;
tmp = strtok(NULL, " ");
stringstream ss_cost(tmp);
ss_cost >> new_product.cost;
//cout << "cost: " << tmp << endl;
//cout << "cost: " << new_product.cost << endl;
product_list.push_back(new_product);
}
It depends on what's in the file? If it's text, you can use the redirect operator on a file input stream:
int i;
infile >> i;
If it's binary, you can just read it in to &your_struct.
You have to
0) Create a new instance of productInfo, pinfo;
1) read text (using getline) to the first comma (','), convert this string to an int, and put it into pinfo.item.
2) read text to the next comma and put it into pinfo.details;
3) read text to the endline, convert the string to a double, and put it into pinfo.cost.
Then just keep doing this until you reach the end of the file.
Here is how I would use getline. Note that I use it once to read from the input file, and then again to chop that line at ",".
ostream& operator>>(istream& is, productInfo& pi)
{
string line;
getline(is, line); // fetch one line of input
stringstream sline(line);
string item;
getline(sline, item, ',');
stringstream(item) >> pi.item; // convert string to int
getline(sline, item, ',');
pi.details = item; // string: no conversion necessary
getline(sline, item);
stringstream(item) >> pi.cost; // convert string to double
return is;
}
// usage:
// productInfo pi; ifstream inFile ("inputfile.txt"); inFile >> pi;
N.b.: This program is buggy if the input is
99999,"The Best Knife, Ever!",16.95
Related
Hi guys I'm working on my last assignment of the computer science class. I think I'm doing everything fine but something is wrong. Can you take a look at it and tell what I'm doing wronger here.
here is what I get when I try to submit online on zybooks site:
"Your program produced no output"
Expected:
Ryan Hermle
22.99
Lochness Monster
3.50
Wonder Woman
123456.78
here are instructions from professor:
Constructor:
Takes a string parameter and stores that as fileName. Does not need to do anything else.
append:
Takes a record as a parameter that contains a string and a double
Open an output file stream in append mode using fileName
set its precision to 2 and fixed
Output the name, newline, the money, newline
searchName:
Open an input file stream with fileName
Loop while a getline and a double extraction are successful
if the string parameter is equal to the name read from the getline, then return the double
If the loop finishes without finding anything, return -1 to indicate that name was not found.
getData:
Open an input file stream with fileName
Construct an ostringstream
Set its precision to 2 and fixed
Loop while a getline and a double extraction are successful
ignore the \n left by the >> extraction
write the string, newline, double, newline to the ostringstream
return the string contained by the ostringstream
here is my main:
#include "Database.h"
int main()
{
Database db("data.txt");
db.append(Record{"Ryan Hermle", 22.99});
db.append(Record{"Lochness Monster", 3.50});
db.append(Record{"Wonder Woman", 123456.78});
}
and here is my Database.cpp file:
#include "Database.h"
Database::Database(string file)
{
fileName = file;
}
void Database::append(Record data)
{
ofstream out;
out.open(fileName, ios::app);
out << setprecision(2) << fixed;
cout << data.name << endl;
cout << data.money << endl;
out.close();
}
double Database::searchName(string n)
{
Record s;
ifstream in;
in.open(fileName);
while (getline(in, n) >> s.money)
{
in.ignore();
if (n == s.name)
{
return s.money;
}
}
return -1;
}
string Database::getData()
{
Record s;
ifstream ifs;
ifs.open(fileName);
ostringstream oss;
oss << setprecision(2) << fixed;
while(getline(ifs, s.name) >> s.money)
{
ifs.ignore();
oss << s.name << endl << s.money << endl;
cout << oss.str();
}
return oss.str();
}
Thanks for everyone who replied to my post. I was able figure out the error in my program.
The error was in append Function:
cout << data.name << endl;
cout << data.money << endl;
It should be like this:
out << data.name << endl;
out << data.money << endl;
I am trying to store strings from a file into a vector containing an array. The following is my way of getting information into the vector:
{
string line;
int nooflines = 0;
ifstream myFile("SongListFile.txt");
while (getline(myFile, line)) {
nooflines++;
}
song temp;
myFile.open("SongListFile.txt");
for (int i = 0; i < nooflines; i++) {
myFile >> temp.title;
myFile >> temp.artist;
myFile >> temp.genre;
songs.push_back(temp);
}
myFile.close();
}
And this is how im trying to print this information:
void SongList::ViewSongList() {
int last_element_position = songs.size() - 1;
for (int i = last_element_position; i >= 0; i--)
{
cout << "\"" << songs[i].title << "\" by " << songs[i].artist << " (" << songs[i].genre << ")" << endl;
}
Why are the strings printing as if they contain nothing? Two of the templates print when there are two lines of text, so my problem is the strings not being stored in my array.
}
Apart that you could do the reading in one pass, as indicated in comments and other answers, the way you are "re-opening" the file is not correct. After the first pass a flag of your ifstream has been set when reaching the end of the file. Opening again the file (without closing) wont clear the flag.
You need either to myFile.close() before re-opening, or alternatively clear the flags then seek to the beginning:
myFile.clear(); // clear the flags
myFile.seekg(0, ios::beg); // seek back to beginning for the second pass
You don't need to count the number of lines in the file at all. You can do it in one pass :
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <string>
using namespace std;
struct Song { string title, artist, genre; };
int main() {
ifstream myFile;
myFile.open("songList.txt");
string aLine;
vector<Song> songs;
while(getline(myFile, aLine)) {
stringstream sin(aLine);
Song aSong;
sin >> aSong.title >> aSong.artist >> aSong.genre;
songs.push_back(aSong);
}
for(int i = 0; i < songs.size(); i++)
cout << "\"" << songs[i].title << "\" by " << songs[i].artist << " ("
<< songs[i].genre << ")" << endl;
return 0;
}
I want to read a name like "Penelope Pasaft" all together from a file and save it to a variable "person". I have understood that I have to use the get line(file, person). But I have a problem doing it because I want also to read other variables before.
Imagine a .txt like:
1
+546343864246
Penelope Pasaft
So here is the code:
typedef struct {
string number; //I use string because it is an alphanumeric cellphone number
string person;
int identifier;
} cellphone;
ifstream entry;
entry.open(fileName.c_str());
cellphone c[10];
int j=0;
if(entry)
{
cout << "The file has been successfully opened\n\n";
while(!entry.eof())
{
entry >> c[j].identifier >> c[j].number;
getline(entry,c[j].person);
cout << "Start: " << c[j].identifier << "\nNumber: " <<
c[j].number << "\nPerson: " << c[j].person << endl << endl;
j++;
}
}
Well the problem I have it's that it doesn't seem to print or save me any data to the variable c[j].person
Problem is that your input file has empty lines in it.
If you use cin >> only, it will work OK because >> operator skips blank chars (but stops at blank chars, as you noted: can't have it all)
On the other hand, getline will read the line, even if it's blank.
I propose the following standalone code slightly modified from yours: note the loop until end of file or non-blank line.
(note: it there are spaces only in the line, it will fail)
I also replaced array by a vector, resized on the fly (more C++-ish)
#include<iostream>
#include<fstream>
#include<string>
#include<vector>
using namespace std;
typedef struct {
string number; //I use string because it is an alphanumeric cellphone number
string person;
int identifier;
} cellphone;
int main()
{
ifstream entry;
string fileName = "file.txt";
entry.open(fileName.c_str());
vector<cellphone> c;
cellphone current;
int j=0;
if(entry)
{
cout << "The file has been successfully opened\n\n";
while(!entry.eof())
{
entry >> current.identifier >> current.number;
while(!entry.eof())
{
getline(entry,current.person);
if (current.person!="") break; // stops if non-blank line
}
c.push_back(current);
cout << "Start: " << c[j].identifier << "\nNumber: " << c[j].number << "\nPerson: " << c[j].person <<endl<<endl;
j++;
}
}
return 0;
}
output:
The file has been successfully opened
Start: 1
Number: +546343864246
Person: Penelope Pasaft
I am trying to read the contents of a text file into a 2D string array, but no matter what I have tried or searched, I can not find a solution. The code is supposed to load a text file separate it into elements by finding horizontal tabs and display the output. When I run the code as is, I receive an error that I found out from searching online, means that I'm trying to manipulate memory I shouldn't be. I'm not asking for the code to be written, just a push in the right direction. Thank you in advance.
this is what I get when I run the program:
0x23fd5c
Process returned -1073741819 (0xC0000005) execution time : 2.344 s
Press any key to continue.
EDIT:: I have corrected the code so it now functions as it should, but it is not storing the last entry of each line in the text file correctly. I can somehow display the number 100 which is the last entry, but when I try to pass that location or display just playList[0][5] , it says it is equal to the first entry of the next line. Any help would be amazing I posted the current code below.
here is my code:
#include <iostream>
#include <string>
#include <iomanip>
#include <cstdlib>
using namespace std;
void readTextFile( int &Count, string playList[50][5]);
void userAddition( int &Count, string playList[50][5]);
int main()
{
string decision;
string playList[50][5];
int Count = 0;
readTextFile(Count, playList);
cout << "If you would like to add to the list, Please enter 'Y'. If you would like to exit
please enter 'N'. ----> ";
getline(cin, decision);
if (decision=="y" || decision=="Y")
userAddition(Count, playList);
else
{
return(0);
}
return 0;
} // End of Main FN.
void readTextFile( int &Count, string playList[50][5])
{
string inputfield;
ifstream infile("c:\\cTunes.txt", ifstream::in);
if ( infile.is_open() )
{
// File is read.
} // end if
else
{
cout << "Error Opening file" << endl;
return; //Program Closes.
} // end else
cout << setw(30)<<left<< "TITLE"<< setw(10) <<left<<"LENGTH"<<
// Outputs a title to each column that is displayed.
setw(40)<< left<<"ARTIST"<< setw(40) << left<<"ALBUM"<<
setw(15) << left <<"GENRE" << setw(5) << left << "RATING" << endl;
getline(infile, inputfield, '\t'); // read until tab
while(! infile.eof()) // loop until file is no longer valid.
{
playList[Count][0] = inputfield;
getline(infile, inputfield, '\t'); // read until tab.
playList[Count][1] = inputfield;
getline(infile, inputfield, '\t'); // read until tab.
playList[Count][2] = inputfield;
getline(infile, inputfield, '\t'); // read until tab.
playList[Count][3] = inputfield;
getline(infile, inputfield, '\t'); // read until tab.
playList[Count][4] = inputfield;
getline(infile, inputfield); // read until end of line.
playList[Count][5] = inputfield;
cout << setw(30)<<left<< playList[Count][0] << setw(10) <<left<<playList[Count][1] <<
// Output the line number equal to count.
setw(40)<< left<<playList[Count][2] << setw(40) << left<< playList[Count][3] <<
setw(15) << left << playList[Count][4] << setw(5) << left << playList[Count][5] <<
endl;
/*cout <<"Title: " << setw(25)<<left<< playList[Count][0]<<endl;
cout <<"Length: " << setw(5) <<left<<playList[Count][1] << endl;
cout <<"Artist: " << setw(50)<< left<<playList[Count][2] << endl;
cout <<"Album: " << setw(40) << left<< playList[Count][3] << endl;
cout <<"Genre: " << setw(15) << left << playList[Count][4] << endl;
cout <<"Rating: " << setw(5) << left << playList[Count][5] << endl<<endl;*/
Count++; // Increment counter by 1
getline(infile, inputfield, '\t'); // read next line until tab.
} // end while
infile.close(); // close the file being read from.
cout<<endl<<endl<<playList[0][5]<<endl;
} // End of readTextFile
I believe getline is causing the problem when reading till the end of the line but I'm truly at a loss.
First, note that in the following line:
cout << playList << endl;
you are printing the address of the array, not the contents. you will need
a loop to print the contents.
Second, in the following code:
if ( infile.is_open() )
{
// ok, read in the file
} // end if
else
{
cout << "Error Opening file" << endl;
//a return statement is missing
}
you need a return statement to avoid reading from a closed stream (which can cause a crash)
Finally, your function does not return anything, so it should either be declared void
or return some value (in which there is no sense according to the context).
Hope that helps and good luck!
The readTextFile function does not return anything. You need to return a string. If you are getting the error what(): basic_string::_S_construct null not valid then this is your problem. You can avoid similar problems by using -Wall compiler option.
You are using std::string for storing the string, std::ifstream for reading from a file, std::getline for reading words... you should really use std::vectors instead of arrays:
typedef std::vector<std::string> Line;
std::vector<Line> playList;
It will make things easier for you.
I also recommend you to change the way you read from a file to:
while(getline(...))
{
...
}
But since you are not allowed to use std::vector, your function could look like this:
// reads the content of input file and stores it into playList:
void readTextFile(std::ifstream& infile, std::string playList[][5])
{
std::string line;
for (int lineIndex = 0; getline(infile, line); ++lineIndex)
{
// skip empty lines:
if (line.empty()) continue;
std::string word;
std::istringstream lineStream(line);
for (int wordIndex = 0; getline(lineStream, word, '\t'); ++wordIndex)
{
// skip empty words:
if (line.empty()) continue;
playList[lineIndex][wordIndex] = word;
}
}
}
that could be used like this:
std::string playList[19][5];
std::ifstream infile("c:\\Test.txt");
if (infile.is_open())
{
readTextFile(infile, playList);
infile.close();
}
else
std::cout << "Error Opening file" << std::endl;
Also note that cout << playList << endl; outputs the address of the first word. To print all words, you will have to write a loop.
I'm making a program for my c++ class. Ultimately I want my program to perform a quicksort on a text file of contacts in the following format:
Firstname Secondname Number
Each contact is separated by a new line. I've started by counting the number of lines and using dynamic memory allocation to create an array of structs which has the same size as the number of lines.
However, when I tried to read in the information from the text file and output it to the screen, all I get is gibberish. I've had a look around on the internet to try and find a solution but everything I've found seems to use a different syntax to me.
Here's my code so far:
#include <iostream>
#include <fstream>
#include <istream>
char in[20];
char out[20];
using namespace std;
struct contact
{
char firstName[14];
char surName[14];
char number[9];
};
//structure definition
int main(void){
cout << "Please enter the input filename: " << endl;
cin >> in;
ifstream input(in);
if(!input){
cerr << "failed to open input file " << in << endl;
exit(1);
}
cout << "Please enter tne output filename: " << endl;
cin >> out;
// read in the input and output filenames
char a;
int b=0;
while (input.good ())
{
a=input.get ();
if (a=='\n')
{
b++;
}
}
// count the number of lines in the input file
input.seekg (0, ios::beg);
//rewind to beginning of file
contact* list = new contact[b];
//dynamically create memory space for array of contacts
int i = 0.;
while(input){
if(i >= b) break;
if(input >> *list[i].firstName >> *list[i].surName >> *list[i].number) i++;
else break;
}
input.close();
//read information from input file into array of contacts
for(int N = 0; N < b; N++){
cout << list[N].firstName << list[N].surName << list[N].number << endl;
}
ofstream output(out);
int k = 0;
for(int k = 0; k<b; k++){
output << list[k].firstName << " " << list[k].surName << " " << list[k].number << endl;
}
//print out the unsorted list to screen and write to output file
//i've done both here just to check, won't print to screen in final version
output.close();
delete []list;
} // end of main()
You reset the files location to the beginning, but the files eofbit is still labeled as true from when you first read the amount of lines. A quick fix to this is re-opening the file after you read the lines, possibly making the line count a function to clean up code.
int lines(const string path)
{
ifstream tmp(path.c_str());
string temp;
int count = 0;
getline(inFile,temp);
while(inFile)
{
count++;
getline(inFile,temp);
}
tmp.close();
return count;
}
Okay, I put together a quick and dirty method using newer C++ constructs to get you most of the way there. You're on your own for writing to the file (trivial) and the quicksort, though I've put the struct into a vector for you, so sorting the vector is as easy as writing a custom function to compare one struct vs the other. I apologize in advance if some of the code is less than canonical C++. I'm way past my bed time, and way tired, but this was interesting enough of a problem that I wanted to give it a go. Happy coding!
#include <iostream>
#include <fstream>
#include <istream>
#include <string>
#include <vector>
#include <algorithm>
#include <cctype>
#include <sstream>
using namespace std;
std::vector<std::string> &split(const std::string &s, char delim, std::vector<std::string> &elems) {
std::stringstream ss(s);
std::string item;
while(std::getline(ss, item, delim)) {
elems.push_back(item);
}
return elems;
}
std::vector<std::string> split(const std::string &s, char delim) {
std::vector<std::string> elems;
return split(s, delim, elems);
}
struct contact
{
std::string firstName;
std::string surName;
std::string number;
contact(std::string& fName, std::string& lName, std::string& num) : firstName(fName), surName(lName), number(num) {}
};
//structure definition
char in[20];
char out[20];
int main()
{
std::vector<contact> contacts;
cout << "Please enter the input filename: " << endl;
cin >> in;
ifstream input(in);
if(!input){
cerr << "failed to open input file " << in << endl;
exit(1);
}
cout << "Please enter tne output filename: " << endl;
cin >> out;
std::string sinput;
// read in the input and output filenames
while (input.good ())
{
getline(input, sinput);
vector<string> tokens = split(sinput, ' ');
if (tokens.size() == 3)
{
contact c(tokens[0], tokens[1], tokens[2]);
contacts.push_back(c);
}
}
input.close();
//read information from input file into array of contacts
std::cout << "Outputting from vector..." << std::endl;
for_each(contacts.begin(), contacts.end(), [](contact& c) {
cout << c.firstName << " " << c.surName << " " << c.number << endl;
});
return 0;
}
Also, just want to give credit that the split methods come from this answer on this very site. Cheers!