Outputting Data From A File Into Structs And Arrays Of Structs - c++

I am having a lot of trouble being able to get data from a file and input it into given structs and arrays of structs and then outputting the file. We are given a file that contains 96 lines and looks like this:
Arzin, Neil
2.3 6.0 5.0 6.7 7.8 5.6 8.9 7.6
Babbage, Charles
2.3 5.6 6.5 7.6 8.7 7.8 5.4 4.5
This file continues for 24 different people and then repeats with different scores (the second line).
The first number, in this case is 2.3 for both people is a difficulty rating. The next 6 numbers are scores.
We are given this data in order to set up our structs and arrays and my code:
#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>
#include <cmath>
using namespace std;
int main ()
{
ifstream inFile;
inFile.open("C://diveData.txt");
// checking to see if file opens correctly
if (!inFile)
{
cout << "Error opening the file!" << endl;
}
const int numRounds = 2; // variable to hold the number of rounds
const int numScores = 7; // variable to hold the number of rounds
const int numDivers = 24; // variable to hold the number of divers
typedef double DifficultyList[numRounds]; // 1D array for storing difficulty of dives on each round
typedef double ScoreTable [numRounds] [numScores]; // 2D array of dive scores
// struct to store information for one diver
struct DiverRecord
{
string name;
double totalScore;
double diveTotal;
DifficultyList diff;
ScoreTable scores;
};
DiverRecord DiverList[numDivers];
// my attempt at printing out the contents of the file
while (!EOF)
{
for (int x = 0; x < 25; x++)
{
infile >> DiverList[x].name;
inFile >> DiverList[x].totalScore;
inFile >> DiverList[x].diveTotal;
cout << DiverList.[x].name << endl;
cout << DiverList.[x].totalScore << endl;
cout << DiverList.[x].diveTotal << endl;
}
}
return 0;
}

First of all the >> operator ends input at the first whitespace character so when you read in the name you only get the last name and the comma it will try to put the first name into totalScore. To get the full name do the following.
string temp;
infile >> DiverList[x].name;
infile >> temp;
DiverList[x].name + " ";
DiverList[x].name + temp;
Also when outputting you don't need that extra '.'
cout << DiverList[x].name << endl;
and so on should work just fine.

Couple of questions:
decide whether ifstream is open or not, use ifstream::is_open;
decide whether end of file is encountered, try code below;
If I get it right, your input file format should be:
name1,name2
difficulty score1 score2 ... score7
In this sense, the totalScore should not be input from the stream, but calculated instead.
you have two names for one record, so the definition of your record structure seems fuzzy.
Here is a revised version:
#include <string>
#include <vector>
#include <fstream>
#include <iostream>
using namespace std;
struct DiverRecord
{
string a, b;
double totalScore;
double difficulty;
double scores[7];
};
int main ()
{
ifstream inFile("C://diveData.txt");
// checking to see if file opens correctly
if (!inFile.is_open()) {
cout << "Error opening the file!" << endl;
}
vector<DiverRecord> DiverList;
DiverRecord record;
char ch;
while (inFile) {
inFile >> record.a >> ch >> record.b >> record.difficulty;
record.totalScore = 0;
for (int i = 0; i < 7; ++i) {
inFile >> record.scores[i];
record.totalScore += record.scores[i];
}
DiverList.push_back(record);
}
// output your DiverList here.
return 0;
}

As I said in my earlier comment I am now trying to concentrate on not using the structs and arrays of structs and am trying to use other functions in order to read the data from the file. I want to put the data in a logical form such as:
Name Of Person
Round 1: Difficulty Scores
Round 2: Difficulty Scores
But I am having trouble accessing specific elements from the file.
The code I am using is:
while(inFile)
{
string name;
getline(inFile, name);
cout << name << endl;
}
This outputs the data file as is, but when I try to declare different variables for the difficulty and the seven scores it does not output correctly at all.

Related

How to simulate user input in c++? [duplicate]

If we have this code snippet:
int a;
cout << "please enter a value: ";
cin >> a;
And in the terminal, the input request would look like this
please enter a value: _
How can I programatically simulate a user's typing in it.
Here's a sample how to manipulate cin's input buffer using the rdbuf() function, to retrieve fake input from a std::istringstream
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
int main() {
istringstream iss("1 a 1 b 4 a 4 b 9");
cin.rdbuf(iss.rdbuf()); // This line actually sets cin's input buffer
// to the same one as used in iss (namely the
// string data that was used to initialize it)
int num = 0;
char c;
while(cin >> num >> c || !cin.eof()) {
if(cin.fail()) {
cin.clear();
string dummy;
cin >> dummy;
continue;
}
cout << num << ", " << c << endl;
}
return 0;
}
See it working
Another option (closer to what Joachim Pileborg said in his comment IMHO), is to put your reading code into a separate function e.g.
int readIntFromStream(std::istream& input) {
int result = 0;
input >> result;
return result;
}
This enables you to have different calls for testing and production, like
// Testing code
std::istringstream iss("42");
int value = readIntFromStream(iss);
// Production code
int value = readIntFromStream(std::cin);
Hey why don't you write your input in a plain text file and redirect it to cin ???
It's the simplest method.
Open Command Prompt.
Suppose your text file which will used as input is in.txt and your program is prog.exe.
Keep the text file and the program in same folder. cd to your folder. Then type:
prog.exe < in.txt
Remember, your text file will be treated exactly as it is. Shoudld't be a problem if you know cin only catches upto next whitespace character, while string input functions (e.g. cin.getline) only catch upto next newline character.
//Sample prog.cpp
#include <iostream>
using namespace std;
int main()
{
int num;
do
{
cin >> num;
cout << (num + 1) << endl;
}
while (num != 0);
return 0;
}
//Sample in.txt
2
51
77
0
//Sample output
3
52
78
1
Sorry if you are on other platform, I don't know about them.

C++ : initialize input programmatically

If we have this code snippet:
int a;
cout << "please enter a value: ";
cin >> a;
And in the terminal, the input request would look like this
please enter a value: _
How can I programatically simulate a user's typing in it.
Here's a sample how to manipulate cin's input buffer using the rdbuf() function, to retrieve fake input from a std::istringstream
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
int main() {
istringstream iss("1 a 1 b 4 a 4 b 9");
cin.rdbuf(iss.rdbuf()); // This line actually sets cin's input buffer
// to the same one as used in iss (namely the
// string data that was used to initialize it)
int num = 0;
char c;
while(cin >> num >> c || !cin.eof()) {
if(cin.fail()) {
cin.clear();
string dummy;
cin >> dummy;
continue;
}
cout << num << ", " << c << endl;
}
return 0;
}
See it working
Another option (closer to what Joachim Pileborg said in his comment IMHO), is to put your reading code into a separate function e.g.
int readIntFromStream(std::istream& input) {
int result = 0;
input >> result;
return result;
}
This enables you to have different calls for testing and production, like
// Testing code
std::istringstream iss("42");
int value = readIntFromStream(iss);
// Production code
int value = readIntFromStream(std::cin);
Hey why don't you write your input in a plain text file and redirect it to cin ???
It's the simplest method.
Open Command Prompt.
Suppose your text file which will used as input is in.txt and your program is prog.exe.
Keep the text file and the program in same folder. cd to your folder. Then type:
prog.exe < in.txt
Remember, your text file will be treated exactly as it is. Shoudld't be a problem if you know cin only catches upto next whitespace character, while string input functions (e.g. cin.getline) only catch upto next newline character.
//Sample prog.cpp
#include <iostream>
using namespace std;
int main()
{
int num;
do
{
cin >> num;
cout << (num + 1) << endl;
}
while (num != 0);
return 0;
}
//Sample in.txt
2
51
77
0
//Sample output
3
52
78
1
Sorry if you are on other platform, I don't know about them.

How to parse a line from the text file

So we have a text file with the following data:
Year - Make - Model - Price
2011 Chevrolet Tahoe $30588
There is only 1 space between everything. There is a Dollar Sign ($) in front of the price. We still have to have miles in our code, even if it's not in the data file. I don't know why.
How would I go about getting this information from a text file?
I have tried a bunch of methods, and none of them seem to work.
Here is the code that grabs the information:
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <ctime>
#include "car.h"
using namespace std;
const int number=3;
const int maxPrice=25000;
int main()
{
int a;
string b; string c;
float d;
float e;
car cars [number];
int i, j;
float temp; //Price
int temp2; //Year
string temp3; //Make
string temp4; //Model
float temp5; //Miles
ifstream inFile; //declaring the File
inFile.open("carData.txt");
for(i=0; i<number; i++)
{
//cout << "Enter the YEAR of the car: ";
inFile >> a;
cars[i].setYear(a);
//cout << "Enter the MAKE of the car: ";
getline(inFile,b);
cars[i].setMake(b);
//cout << "Enter the MODEL of the car: ";
getline(inFile,c);
cars[i].setModel(c);
//cout << "Enter the number of MILES on the car: ";
inFile >> d;
cars[i].setMiles(d);
//cout << "Enter the PRICE of the car: ";
inFile >> e;
cars[i].setPrice(e);
//cout << " " << endl;
}
// ...
}
The main continues much further than that, this is just to getline all of the data. I've really been having trouble with this all day. I've seen so many different methods.
If you used a standard parsing function, such as std::fscanf, then you could
take away a lot of your pain. You can find out more about *scanf() and friends
from http://en.wikipedia.org/wiki/Scanf_format_string and http://www.cplusplus.com/reference/cstdio/fscanf/.
I normally write C (or python, i'm not choosy ;>) so I'd come up with something
like this:
infile = open("datafile");
res = 0;
while (res != EOF) {
res = fscanf(infile, "%d %d %s %s %d",
&price, &year, &model, &model, &miles);
if (res < 0) {
/* error condition from fscanf() */
(void) fprintf(stderr, "error (%d) from fscanf: %s\n",
res, strerror(res));
exit(res);
}
}
[BTW, the reason exercises like these typically require 'miles' (which are
featured in the data snippet you gave, it's missing the final column) is because
they usually want you to build on these for ranking the cars based on miles or
km travelled vs price vs age].
Ok, so I know it is a bit late but here is a way to achieve your desired results, if you haven't done it already, in c++
The problem is that std::getline will put in the argument string the whole line
So if you have something like this
std::getline(inFile, temp3)
The temp3 will have the value: "Year - Make - Model - Price".
This also sets the cursor to the next line so if you repeat the function
std::getline(inFile, temp3)
then temp3 will be equal to "" as the line after the first is empty(at least in the file that you used as an example).
Now to work around this you need to use a stringstream that is a stream but reads it's values from a , drum rolls please, string.
So the basic idea is this:
1->Go to the line that contains the information
2->Use a stringstream to read the data()
Here is an implementation of that idea:
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
using namespace std;
int main()
{
int a;
string b; string c;
float d;
float e;
//This assumes that the array is correctly initialized
car cars [number];
string tempLine;
ifstream inFile;
inFile.open("carData.txt");
//get the cursor past the first line that contains the column names
std::getline(inFile, tempLine)
//get the cursor past the second line that is blank
std::getline(inFile, tempLine)
//Now we are at the line that interests us
//I am assuming that the next lines don't have a blank line between them
unsigned int = 0;
int numberOfMiles;
while(std::getline(inFile, tempLine) && i<number)
{
std::stringstream iss(tempLine)
string tempPrice; //this will be the price value with the dollar sign
//you can also write in expanded form this read, but this works just fine
iss>>a>>b>>c>>numberOfMiles>>tempPrice; //notice that the price is now a string
tempPrice.erase(0,1)//this eliminates the dollar($) sign
std::stringstream iss1(tempPrice)//new stringstream as we need to read this string
iss1>>temp;//I believe this is your price variable
cars[i].setYear(a);
cars[i].setMake(b);
cars[i].setModel(c);
cars[i].setMiles(numberOfMiles);
cars[i].setPrice(temp); //i am assuming that this is how the function in called
i++;
}
}
Hope this helps.

How to print specific array entries from a .txt file in C++?

First, I'm very new to coding in C++.
So, I have a .txt file, with names and numbers--here's an example.
chris 5
tara 7
Sam 13
Joey 15
I would like to use this code to retrieve the names and numbers, but how does one print specific array entries instead of just the variables name and number (I want it to show the name and the number on the screen)?
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main() {
string name;
int number;
struct sEntry
{
std::string name;
int number;
};
sEntry entries[256];
std::ifstream fin("input.txt"); // opens the text file
int nb_entries; // Keeps track of the number of entries read.
for (nb_entries = 0; fin.good() && nb_entries < 256; nb_entries++) // Keep going until we hit the end of the file:
{
fin >> entries[nb_entries].name;
fin >> entries[nb_entries].number;
cout << "Here, "<< name <<" is name.\n";
cout << "Here, "<< number <<" is number.\n";
}
}
You're writing out name and number, but those aren't the variables you've read. You've read array entries.
Getting it working as simply as possible just comes down to changing your cout lines to be:
cout << "Here, " << entries[nb_entries].name << " is name.\n";
cout << "Here, " << entries[nb_entries].number << " is number.\n";
No need for a std::vector, ther's nothing wrong with how you've done it.
Instead of using a plain C array of sEntry you should use a C++ vector instead (which can change size dynamically). Then you create a new sEntry instance inside your loop (which can just use fin.eof() as termination condition then) and use the operator>>() to assign the values. Afterwards you use push_back() to add the sEntry instances to your vector.
You need to use the sEntry.name, sEntry.number fields for output on the screen, name and number as shown in your code won't ever receive values.
#include <vector>
#include <string>
#include <iostream>
struct sEntry
{
std::string name;
int number;
};
int main() {
string name;
int number;
std::vector<sEntry> entries;
std::ifstream fin("input.txt"); // opens the text file
// int nb_entries; // Keeps track of the number of entries read. -> not necessary, use entries.size()
while(!fin.eof()) // Keep going until we hit the end of the file:
{
sEntry entry;
fin >> entry.name;
fin >> entry.number;
cout << "Here, "<< entry.name <<" is name.\n";
cout << "Here, "<< entry.number <<" is number.\n";
entries.push_back(entry);
}
}

Detect newline byte from filestream

I'm trying to collect information from a textfile which contains names of organisations (without spaces) and floating integers. I want to store this information in an array structure.
The problem I'm having so far is collecting the information. Here is a sample of the textfile:
CBA 12.3 4.5 7.5 2.9 4.1
TLS 3.9 1 8.6 12.8 4.9
I can have up to 128 different numbers for each organisation, and up to 200 organisations in the textfile.
This is what my structure looks like so far:
struct callCentre
{
char name[256];
float data[20];
};
My main:
int main()
{
callCentre aCentre[10];
getdata(aCentre);
calcdata(aCentre);
printdata(aCentre);
return 0;
}
And the getdata function:
void getdata(callCentre aCentre[])
{
ifstream ins;
char dataset[20];
cout << "Enter the name of the data file: ";
cin >> dataset;
ins.open(dataset);
if(ins.good())
{
while(ins.good())
{
ins >> aCentre[c].name;
for(int i = 0; i < MAX; i++)
{
ins >> aCentre[c].data[i];
if(ins == '\n')
break;
}
c++;
}
}
else
{
cout << "Data files couldnt be found." << endl;
}
ins.close();
}
What I'm trying to achieve in my getdata function is this: store the organisation name first into the structure, then read each float into the data array until the program detects a newline byte. However, so far my check for the newline byte isn't working.
Assume that variables c and MAX are already defined.
How should I go about this properly?
The >> operator treats whitespace as a delimiter, and that includes newlines, so it just eats those and you never see them.
You need to read lines and then chop the lines up. The following bit of hackery illustrates the basic idea:
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
int main() {
string line;
while( getline( cin, line ) ) {
istringstream is( line );
string cs;
is >> cs;
double vals[10];
int i = 0;
while( is >> vals[i] ) {
i++;
}
cout << "CS: " << cs;
for ( int j = 0; j < i; j++ ) {
cout << " " << vals[j];
}
cout << endl;
}
}
char byte = ins.peek();
Or
if(ins.peek() == '\n') break;
(Edit): You'll want to also check for an eof after your peek(), because some files may not have a ending newline.
I'd like to point out that you might want to consider using a vector<callCentre> instead of a static array. If your input file length exceeds the capacity of the array, you'll walk all over the stack.
I would read the file, one line after another and parse each line individually for the values:
std::string line;
while (std::getline(ins, line)) {
std::istringstream sline(line);
sline >> aCentre[c].name;
int i = 0;
while (sline >> aCentre[c].data[i])
i++;
c++;
}