2D array of structs - c++

Description:
This program will read a data file that will contain students’ scores for 5
Computer Science (CS) tests. Each student record will contain his/her last name, first
name, numeric student ID, student username, 5 test scores, average for these five scores,
and grade for CS course. The file will be processed by the program and will produce a
report.
The report contains seven parts:
The students’ usernames
The average score for each student’s five tests.
The grade for each student’s CS course.
The average CS scores for the class.
The total number of students with grades A, B, C, D, and F.
The sorted student names and IDs based on user choice: descending or ascending order
of grades.
Search a student grade by entering student user name ID.
(See the attached sample input and output for example.)
Specifications:
All input data will be in an input file. The name of the data file that will be used
for your program MUST BE grade.dat. You may need to create your own
version of grade.dat to test your program before you turn it in. You must also
submit a printout of the contents of this test file when you submit this project.
The student user name is generated by the students’ names and ID numbers
according to the following rule. The student user name will be the first two initials
and the four digits of the student ID number. For example, for student John (last
name), Doe (first name), with ID number 1122, his user name would be: jd1122.
The user names are all lower cases.
Your program needs to use a structure to store the student information including
last name, first name numeric student ID, student user name, 5 test scores,
average for these five scores, and grade for CS course.
Your program needs to write at least three functions in your program: For
example: find average, find grade, search score etc.
2
Your program needs to do input checking: (1) correct input choices for sorting:
ascending or descending; and (2) correct format for user ids: first two are letters
and last four are digits.
Requirements for Submission:
You must
submit your C++ source code, which is .cpp file through myClasses#SU, and hand
in:
Design/pseudocode/hierarchy chart. of your algorithm.
A printed copy of your source code.
Your set of sample input data files
Your set of sample screen outputs corresponding to each input data file.
Program report: state clearly if your program doesn’t work well. What’s the
problem? Or anything you want me to know, for example, you get the help from
other students. You can not copy others’ work. It is individual program
assignment!
You will need to be ready to demo your project and ready to answer any questions
related with the project.
Grading Rubric:
Algorithm design/Pseudocode 10
Correct outputs 20
Structures 20
Functions 10
File reading 10
Input checking 10
Searching and sorting 10
Readability/comments of program (including project report) 10
3
Sample Run
Sample Input File grade.dat contains:
Bonebrake Nicole 1111 90 85 50 78 85
Boyer Dennie 2222 100 90 99 89 88
Bozick Julia 3333 52 85 44 66 87
Carroll Sandra 4444 87 88 95 85 100
Creighton Sarah 5555 91 55 80 88 75
Everett Terry 6666 60 70 59 79 89
Freeman Andrew 7777 92 95 94 96 97
Fugett Brandon 8888 77 88 75 95 80
Here is what I have so far:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
struct StudentData
{
string first;
string last;
int studentID;
int exam1;
int exam2;
int exam3;
int exam4;
int exam5;
};
int main()
{
ifstream file;
file.open("grade.dat");
StudentData students[8][8];
file.close();
}
I am having trouble bringing the data out of the file and putting it into an array.

What about the following:
#include <iostream>
#include <fstream>
#include <string>
#include <cstring>
#include <cstdio>
using namespace std;
struct StudentData
{
string first;
string last;
int studentID;
int exam1;
int exam2;
int exam3;
int exam4;
int exam5;
};
int main()
{
ifstream file;
string temp;
char fname[100];
char lname[100];
file.open("grade.dat");
StudentData students[8];
for (int i = 0; i<8; i++)
{
getline(file, temp);
sscanf(temp.c_str(),"%s %s %d %d %d %d %d %d", fname,lname,&students[i].studentID
,&students[i].exam1,&students[i].exam2,
&students[i].exam3,&students[i].exam4,&students[i].exam5);
students[i].first = fname;
students[i].last =lname;
}
file.close();
for (int i = 0; i<8; i++)
{
cout<<students[i].first<<" "<<students[i].last<<" "<<students[i].studentID
<<" "<< students[i].exam1<<" "<< students[i].exam2<<" "<< students[i].exam3
<<" "<< students[i].exam4<<" "<< students[i].exam5<<endl;
}
}

OK, since all you need is a head start, here are some hints:
First of all, your assignment says nothing about 2d arrays, if you are doing it for extra credit or something - don't, it is not mandated neither by your assignment, nor by the actual task at hand.
Second - your problem at hand - reading the file. You should start by reading it one line at a time. The line contains the names, the id and the grades. Once you have the line, you can extract the fields, by say splitting the string at the spacebars. This will give you a string for every field. Then you can assign the student name fields to the strings. There is also a function that converts strings to integers - that will come in handy for the rest of the fields.
Just to make things look a little more professional, you might want to consider using a container class instead of a plain array, std::vector is a good candidate. Also, if you are going to be sorting, you might want to use pointers (preferably smart pointers) and dynamic memory allocation. Also, in order to be able to sort your array, you will need to write functions which compare students based on different criteria. A container will give you an easy way to add and remove students, instead of some stiff static construct.
Every step of the way is already covered in answers here on SO, so all you need to get things done is search whenever you get stuck.

Related

Read a file in by columns in C++

I have a file that contains numbers:
23 899 234 12
12 366 100 14
10 256 500 23
14 888 564 30
How can I read this file by column using C++? I searched YouTube but they only read file by row. If I have to find the highest value from the first column, I need to read it by columns right?
Try initialising a variable called column =0
Now when you access row iterate through column using a for loop until end of column which can be found out by no of lines in a file, then implement the operation what you are willing to do, now increase column no for going to next column.
And you can get value in form of n*vectors
Where n is no of rows
Dimension of vector is length of column
Files are storages with sequential access, so , generally you have to read everything. Essentially it's like reading from a tape. And format of your file doesn't offer any shortcuts.
But, you can fast-forward and rewind along file, using seek() if it's a file on permanent storage. It's not effective and you have to know position where to go. If your records are of same size, you can advance by fixed amount of bytes.
That is usually done with binary formats and those formats are designed to have some kind directory or other auxiliary data to help searching for proper position..
Read each line and split it by space and store the first value as highest value. repeat the steps for all rows until you reach end of file while comparing the first value again with already stored value as highest.
I don't have C++ compiler available with myself to test. it should work for you conceptually.
#include <fstream>
#include <string>
#include <iostream>
#include<sstream>
using namespace std;
int main() {
ifstream inFile("Read.txt");
string line;
int greatest = 0;
while (getline(inFile, line)) {
stringstream ss(line);
string FirstColumn;
while (ss >> FirstColumn) {
if (stoi(FirstColumn) > greatest)
greatest = stoi(FirstColumn);
}
cout << greatest << endl;
}
}

Understanding How to Read Into A File & Separate Lines from File into Different Variables

So here's my dilemma. I have this homework assignment due today which involves reading data in from a file, separating the lines into various variables, and displaying the lines based on certain parameters. The issue I (as well as my classmates) are experiencing is that our professor is very bad at teaching and with our projector currently broken, she's not able to teach from the pre-given slides and instead relies 100% on examples she comes up with and explains very little about. Not only this but I've been working away at this for hours, it is currently 4:30 in the morning and I am very bad at programming regardless of professor. I've never been very good and it's actually going to make me change majors because I can't get the hang of it. Basically I just need to get an idea of the steps to take in the right direction because otherwise I'm going to be up all night and will have a miserable rest of the day because of it.
Our assignment involves taking data from a list of farms which also include a number of items, the description of said item, the price per item, and the total cost of said item multiplied by the cost per item all on one line per "complete" listing. If the farm itself has been mentioned previously in the file (duplicates are conveniently placed next to each other) then add the number of items as well as the total price into one single line. So for example, between the 3 listings of "Big Top Farm" would be displayed as one line containing 10,625 total items with a total cost of $5,622.30. At the very end, the code is intended to print out a specific number of "unique" farms that contributed (ones that had repeat entries are only included once). I understand that I could go about this with a simple counter integer with a quick ++ sequence after it reads in a specific set, but that's about the only thing I know I'm doing correctly.
Here's my desperate attempt at code (which yes, I know is unfinished and doesn't build)
#include <fstream>
#include <cstdlib>
#include <string.h>
using std::cin;
using std::cout;
using std::endl;
using std::ifstream;
using std::ofstream;
using std::ios;
using std::string;
//prototypes
void readIn();
int farmDisplay(int, string, double, double);
int main()
{
string farmName, itemType;
int itemCount, farms;
double itemPrice, totalPrice;
cout << "==================================================" << endl;
cout << "= FARMER'S MARKET INVENTORY =" << endl;
cout << "==================================================" << endl;
farms = farmDisplay(itemCount, itemType, itemPrice, totalPrice);
cout << endl;
cout << "There were " << farms << " unique farms contributing to this week's event." << endl;
return 0;
}
//precondition:
//postcondition:
int farmDisplay(int itemCount, string itemType, double itemPrice, double totalPrice)
{
int counter = 0, result, prevItemCount, currentItemCount;
string farmName, prevFarm, currentFarm;
ifstream inFile;
inFile.open("ASSGN6-B.txt");
//Check for Error
if(inFile.fail())
{
cout << "Error opening file..." << endl;
exit(1);
}
while(!inFile.eof())
{
cin.ignore();
getline(inFile, currentFarm, ',');
if(prevFarm.compare(currentFarm) == 0)
{
prevFarm = currentFarm;
prevItemCount == currentItemCount;
counter--;
}
else
{
prevFarm = currentFarm;
prevItemCount == currentItemCount;
}
inFile >> itemCount >> itemType >> itemPrice >> totalPrice;
cout << farmName << " " << itemCount << " items contributed totaling $" << totalPrice << endl;
counter++;
}
inFile.close();
return counter;
}
Here's what the file that we are given looks like:
Collins Farm, 43900 tomatoes 0.67 29413
Bart Smith Farms, 34910 cassavas 0.99 34560.9
Allen Farms, 117 coconuts 0.54 63.18
River Run Farm, 103 taros 0.65 66.95
Big Top Farm, 109 artichokes 2.23 243.07
Big Top Farm, 777 crosns 0.28 217.56
Big Top Farm, 9739 cucumbers 0.53 5161.67
Marble Farm, 108 crosns 0.33 35.64
Food For Life Inc., 106 carrots 0.87 92.22
Food For Life Inc., 86 coconuts 0.84 72.24
Johnson Farms, 121 parsnips 0.22 26.62
A1 Farm, 111 beets 0.12 13.32
A1 Farm, 5591 taros 0.72 4025.52
Looney Tunes Farm, 102 onions 0.49 49.98
Wolfe Creek Farm, 103 rhubarbs 1.21 124.63
Wolfe Creek Farm, 199 radishes 0.71 141.29
James Farm, 47 pickles 0.68 31.96
Weaver Farms, 75 walnuts 2.5 187.5
Weaver Farms, 500 pickles 0.59 295
Pore Boy Farms, 670000 peanuts 0.79 529300
Rutherford Farms Inc., 809 apples 0.9 728.1
Rutherford Farms Inc., 659 pickles 0.7 461.3
Javens Farm, 129000 figs 0.44 56760
Harrison Farms, 8001 yams 1.09 8721.09
Setzer Farms Inc., 701 potatoes 0.89 623.89
Setzer Farms Inc., 651 tomatoes 0.69 449.19
Pikes Peak Farm, 1045 turnips 0.79 825.55
Holland Area Farms, 10001 radishes 0.69 6900.69
Any advice would be greatly appreciated as I feel like I'm going to go insane working on this project any longer
Okay, I'm going to give you a general approach and some basic thoughts. First, coding isn't easy. That's why us old-time programmers have made really nice livings. But you won't just cruise into it. It takes dedication and curiosity. You have to LOVE it, but consider programming one huge puzzle.
Now, when you're overwhelmed by a task, break the task down into smaller pieces. You really kind of made it into one big piece.
Here's what I would do. I would make a class to represent the raw data. I would make a class to load the file, and then I would write a method to analyze the data and put it out.
In this case, start with the classes.
// This holds one line's data
class LineItem {
public:
std::string farmName;
std::string itemName;
int quantitySold;
double priceEach;
double totalPrice;
// You'll need to implement this, see comments below.
LineItem(const std::string fromString);
};
// This holds all the data for a specific farm.
class Farm {
public:
std::string name;
std::vector<LineItem *> lineItems;
};
// And this holds all the farms with the key being the farm name.
std::map<std::string, Farm *> allfarmsByName;
At this point, you need a method to read the data. I would read each line and then split the string at the delimeters (commas and/or spaces). Column 1 is the name, 2 is the quantity, etc.
This is a relatively simple piece of code you should be able to write. So you can getlines of data, then do something like this:
LineItem *newItem = new LineItem(myString);
If you implement that constructor, then you can do this:
Farm * farm = allFarmsByName[newItem->farmName];
if (farm == nullptr) {
farm = new Farm();
farm->name = newItem->farmName;
allFarmsByName.insert(pair<std::string, Farm *>(farm->name, farm));
}
At this point, your allFarmsByName class has one item per contributing farm, and each farm has a vector of all the data.
So, to print how many farms helped this month, you only need to print the size of allFarmsByName.
Now, the specifics of how I do this aren't important. It's the approach. Break it down.
First, envision your data and construct classes to represent the data.
Second, read the data from your file into these objects.
Then do whatever you need to do to perform analysis.
This is a work pattern. Envision data. Read data. Report on data.
You already have an approach for a class implementation using the STL std::vector to hold each of the components of each line as a single unit provided by #JosephLarson. With the class implementation you can provide member functions to operate on the stored data to create an abstraction of what your farm is.
If that is a bit beyond where you are in your learning, you can approach it by keeping two sets of values. One for the current farm you are collecting values for, and a temporary set that you read data from your file into. Instead of two sets of 5 variables each, any time you need to coordinate differing types of data as a single unit, you should be thinking struct or class (both provide the same functionality in C++, the difference being that by default access to struct members are public: whereas the default for class members is private:.
As mentioned in my comments earlier, your current approach of attempting to read data with while(!inFile.eof()) will end if failure. See Why !.eof() inside a loop condition is always wrong.
and Why is iostream::eof inside a loop condition considered wrong?
Instead, for a general approach, rather than trying to read parts of a line with differing calls to getline directly from your file-stream, it is far better to read a complete line at a time and then to create a std::stringstream from the line and parse the information you need from the stringstream. The prevents a partial read or format error from propagating from the point of error to the end of your file.
The approach is straight forward, start as you have, but also include <sstream>. For example, you can include the necessary headers and declare a simple struct to hold the differing parts of each line, declare an instance of the struct for use in your code, validate at least one argument is given to provide a filename, read the filename as the first-argument to your program and open your file stream for reading with:
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
struct farmdata {
std::string name, item;
size_t qty;
double cost, total;
};
int main (int argc, char **argv) {
if (argc < 2) {
std::cerr << "error: filename required as 1st argument.\n";
return 1;
}
farmdata farm = {"", "", 0, 0.0, 0.0};
size_t farmcount = 0;
std::string line;
std::ifstream f (argv[1]);
...
At this point, rather than while(!inFile.eof()), control your read loop with the actual read of the line into the string line, e.g.
while (getline (f, line)) {
...
Now just create a stringstream from line from which you can read name, qty, item, cost & total without any risk of leaving extraneous characters in your stream unread in case of a parsing error or type mismatch. It is quite simple to do. You will also want to declare a temporary instance of your struct to read values into that will allow you to compare the name of the farm with the current farm name you are collecting data for, e.g.
std::istringstream ss (line);
farmdata tmp;
Now just read values into your temporary struct from the stringstream ss just as you would from your file-stream, and then compare values with the current values in farm (note the farm struct was initialized zero to allow a test of whether farm.name.length() is zero indicating the first line is being read into tmp):
if (getline (ss, tmp.name, ',')) {
if (ss >> tmp.qty && ss >> tmp.item && ss >>
tmp.cost && ss >> tmp.total) {
if (farm.name.length() == 0) {
farm = tmp;
farmcount++;
}
else if (tmp.name == farm.name) {
farm.qty += tmp.qty;
farm.total += tmp.total;
}
else {
std::cout << farm.name << " " << farm.qty <<
" items contributed totaling $" << farm.total << '\n';
farm = tmp;
farmcount++;
}
}
}
}
(note: your farmcount is only updated when the name read into tmp differs from farm.name or on the first line read from the file)
After exiting your read loop all that remains is outputting the data for the last farm read from the file and output the total farmcount that participated this week,
std::cout << farm.name << " " << farm.qty <<
" items contributed totaling $" << farm.total << "\n\n";
std::cout << "There were " << farmcount <<
" unique farms contributing to this week's event." << '\n';
}
Example Use/Output
If you implement something similar to the above, you would process your file and receive something similar to:
$ ./bin/farmtotal dat/farms.txt
Collins Farm 43900 items contributed totaling $29413
Bart Smith Farms 34910 items contributed totaling $34560.9
Allen Farms 117 items contributed totaling $63.18
River Run Farm 103 items contributed totaling $66.95
Big Top Farm 10625 items contributed totaling $5622.3
Marble Farm 108 items contributed totaling $35.64
Food For Life Inc. 192 items contributed totaling $164.46
Johnson Farms 121 items contributed totaling $26.62
A1 Farm 5702 items contributed totaling $4038.84
Looney Tunes Farm 102 items contributed totaling $49.98
Wolfe Creek Farm 302 items contributed totaling $265.92
James Farm 47 items contributed totaling $31.96
Weaver Farms 575 items contributed totaling $482.5
Pore Boy Farms 670000 items contributed totaling $529300
Rutherford Farms Inc. 1468 items contributed totaling $1189.4
Javens Farm 129000 items contributed totaling $56760
Harrison Farms 8001 items contributed totaling $8721.09
Setzer Farms Inc. 1352 items contributed totaling $1073.08
Pikes Peak Farm 1045 items contributed totaling $825.55
Holland Area Farms 10001 items contributed totaling $6900.69
There were 20 unique farms contributing to this week's event.
The drawback to simply using a "inch-worm" method of checking the current name read against the last is you are not storing your data in any type of array or vector which limits your ability to sort or otherwise manipulate the complete data set to get the information in any other form other than "as read from the file".
You can also further tailor your output formatting by including the Standard library header <iomanip> header and making use of std::setw() for general field width along with std::fixed and std::count.precision() for floating-point number formatting.
Look things over and let me know if you have further questions.

Is there a problem with my map construction?

My code didn't report a bug. But when run in the online judge system, I was told that it couldn't get right answer for some special samples. I can't figure it out, so I turn to here for help.
Problem Description
Every girl likes shopping,so does dandelion.Now she finds the shop is increasing the price every day because the Spring Festival is coming .She is fond of a shop which is called "memory". Now she wants to know the rank of this shop's price after the change of everyday.
Input
One line contians a number n ( n<=10000),stands for the number of shops.
Then n lines ,each line contains a string (the length is short than 31 and only contains lowercase letters and capital letters.)stands for the name of the shop.
Then a line contians a number m (1<=m<=50),stands for the days .
Then m parts , every parts contians n lines , each line contians a number s and a string p ,stands for this day ,the shop p 's price has increased s.
Output
Contains m lines ,In the ith line print a number of the shop "memory" 's rank after the ith day. We define the rank as :If there are t shops' price is higher than the "memory" , than its rank is t+1.
Sample Input
3
memory
kfc
wind
2
49 memory
49 kfc
48 wind
80 kfc
85 wind
83 memory
Sample Output
1
2
Code:
#include<algorithm>
#include<iostream>
#include<map>
#include<cstdio>
using namespace std;
const int maxn = 10010;
int main(){
int n,m;
map<string ,int> dic ;
char names[maxn][32];
scanf("%d",&n);
for(int i = 0;i<n;i++){
scanf("%s",names[i]);
dic[names[i]] = 0;
}
scanf("%d",&m);
while(m--){
for(int i = 0;i<n;i++){
int temp;
scanf("%d",&temp);
char tp[32];
scanf("%s",tp);
dic[tp] += temp;
}
int ranking = 1;
for(int j = 0;j<n;j++){
if(dic[names[j]]>dic[names[0]]){
ranking++;
}
}
printf("%d\n",ranking);
}
return 0;
}
Although I don't have any problem with the sample, but it Can't pass black box test.

Evaluating Bridge Hands in C++

I am working on a program that is supposed to read in a file (each line in the file represents a hand of 13 cards) and evaluate each bridge hand.
I will ask my specific questions at the end, but because there is a good bit to this program I am going to include all the instructions so you get an idea of what is required.
Here is the text file that will be read in:
2C QD TC AD 6C 3D TD 3H 5H 7H AS JH KH
3C 4C 2D AC QC 7S 7C TD 9C 4D KS 8D 6C
2C 3C KC JC 4C 8C 7C QC AC 5C 9C 6C TC
5H 3S 4D KC 9S 3D 4S 8H JC TC 8S 2S 4C
2S 5D 6S 8S 9D 3C 2H TH
2H 6D %S 8S 7S 4D 3H 4S KS QH JH 5C 9S
2C QD TC AD 6C 3D TD 3C 5H 7H AS JH KD QS
2C QD TC AD 6C 3D TD 2C 5D 7H AS JH KD
2H 6D TS 8Z 7S 4D 3H 4S KS QD JH 5C 9S
With each pair representing a card (the value and the suit).
Legal values include:
2-9
T(10), A(Ace), K(King), Q(Queen), and J(Jack)
And suits:
C(Clubs), S(Spades), D(Diamonds), and H(Hearts)
Once the file is read in, each hand must be sorted first by suit and then by the rank within the suit (aces are high). When the sorting is complete, each hand must be evaluated using the following rules:
Aces = 4
Kings = 3
Queens = 2
Jacks = 1
voids (no cards in a suit) = 3
singletons (one card in a suit) = 2
doubletons (two cards in a suit) = 1
long suits (more than 5 cards in a suit) = 1 count for each card over 5 in number
After being evaluated, each hand should be displayed in the following format:
Example Input:
2C QD TC AD 6C 3D TD 3H 5H 7H AS JH KH
Example Output:
Clubs 10 6 2
Diamonds A Q 10 3
Hearts K J 7 5 3
Spades A
Points = 16
Here are a few specifics about what the program must include:
1. A data structure to hold cards in an ordered manner.
2. A function to read in the hand.
3. A function to evaluate the hand (with support functions).
4. A function to display the hand.
Here is what little code I've been able to come up with. In case it's not clear, the comments are steps I think will need to be done in order for the program to work properly. Right now all it does is open the file, and yes I will be removing the "File is Open" message, I just wanted to be sure the file was actually being open.
//#include <program3.h>
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int main() {
//Create Array
//char bridgeHands[];
//Open file, if it doesn't exist, exit the program
ifstream bridgeFile;
bridgeFile.open("prog3.dat");
if(!bridgeFile) {
cerr << "Open Failure" << endl;
exit(1);
}
else {
//Read file into array
//Sort array
//Evaluate hands
//Display hands
cout << "File is open" << endl;
}
return 0;
}
I guess my specific question at the moment is this. How do I need to go about creating and loading the array? I have never worked with loading an array from input that is in pairs. Also, how does this work with the data structure?
I'm sure you can tell by now that I'm extremely new at this and am learning as I go (pretty much everything I know how to do in C++ is written in that code), so any help is greatly appreciated. Thank you for your time.
There are a lot of open questions in my mind. First and
foremost: should each hand be on a separate line, or is it just
the next 13 cards, regardless of line breaks. This changes the
way you read hands. In either case, your input file has errors
which must be detected: in the first case, the fifth and seventh
lines have an incorrect format, and in the second, the number of
cards isn't a multiple of 13, so there must be an error
somewhere.
Anyway, the proper way to approach this is to define types
(classes) for the cards and the hand, and defined a user defined
operator>> for each, with the operator>> for hands using the
one for cards. For example:
std::istream& operator>>( std::istream& source, Card& object)
{
char value;
char suit;
source >> std::ws; // skip leading whitespace.
source.get(value); // these do _not_ skip whitespace
source.get(suit);
if ( source ) { // no errors on input...
// Map the characters to the internal representation and write
// them into `object`. This operator may have to be a friend
// to do this.
//
// If one of the characters isn't legal:
// source.setstate( std::ios_base::failbit );
}
return source;
}
For the hand, if your input is line oriented, the best solution
is probably to use std::getline to read the line, then
std::istringstream to parse it. Make sure you check that
there is nothing but white space left once you've read the 13
cards. (If the input ignores line endings, then just reading 13
cards should be sufficient.) Regardless of the strategy, be
sure the check for errors after each read, before using the
values you've read. So you're loop (either on the
std::istringstream or the original source, depending) might
look something like:
int i = 0;
while ( i != 13 && source >> dest[i] ) {
++ i;
}
if ( i == 13 ) {
// Input of 13 cards succeeded...
}
Finally: You're input contains errors (probably intentionally,
to ensure that you test them correctly). Which means the
simplest form of the outer loop won't work correctly (since it
will stop at the first error). If we suppose line oriented
input globally, but the >> operator for hand ignores line
endings and just looks for the next 13 Card:
std::string line;
int lineNumber = 0;
while ( std::getline( source, line ) ) {
++ lineNumber;
std::istringstream parser( line );
if ( parser >> hand >> std::ws && parser.get() == EOF) {
// Line is good, hand contains the instance to be evaluated
} else {
std::cerr << "Input format error in line " << lineNumber << std::endl;
}
}
Concering the condition in the if: we read a hand, then skip
white space; if that succeeds, we verify that we have reached
end of file (otherwise, there's extra garbage at the end of the
line). You can give a more detailed error message if you
separate these different operations out, although to indicate
which card is in error, you'll have to input the 13 cards
directly at this level, rather than using the >> for Hand.
One other suggestion: I would choose an internal representation
which made processing simple, with mapping functions for input
and output. This is probably two enums: one for values (with
the values in the order of their ranking), one for suits (also
in the order of their ranking). This will make the sorting
and the counting significantly easier, and mapping functions are
very easy: for small sets like these, nothing more than an array
with the legal representations: on input, a linear search, and
on output, just index. (Note that this may result in the value
2 having the numeric value 0 internally, since it will be
the first value of the enum.)
Use the ifstream::getline() function for reading and parsing the file. At this link you also find a nice example how you might read the file directly into a std::array:
#include <iostream>
#include <sstream>
#include <vector>
#include <array>
int main()
{
std::istringstream input("abc|def|gh");
std::vector<std::array<char, 4>> v;
// note: the following loop terminates when std::ios_base::operator bool()
// on the stream returned from getline() returns false
for (std::array<char, 4> a; input.getline(&a[0], 4, '|'); ) {
v.push_back(a);
}
for (auto& a : v) {
std::cout << &a[0] << '\n';
}
}
But take a close look whether this is suitable for your case. As an alternative you could omit the last parameter of getline so you really get the lines one by one. Then you'd have to parse these lines using std::string::find() and std::string::substr().

Trouble with arrays and I/O files [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
Here is an assignment I an having trouble with. The code I have for the assignment is below. Im not sure why Im not reading in the data from the txt file. can anyone take a look at the assignment and my code and point me in the right direstion?
Assignment
Service Calls Company Report
The OK-Service Handlers Company handles daily service calls from customers, phone calls. The company handles folk’s problems over the phone. The powers to be need a summary on the calls made in a given month.
The data collected is each day’s service calls that come in and is recorded in a file named SericeCalls.txt. I will put the file out on Blackboard under Assignments.
The data indicates the type of service call made and the number of minutes that service call lasted. The company handles several different kinds of calls and each day there will be several different entries for a given call for a given day. The input will be two numbers per line where the first number is the type of service call and the second is the number of minutes that call lasted. Each input line is a record of one service call. There are 25 different types of service rendered and are numbered 1 to 25.
For example:
3 30 service number 3 and lasted 30 min.
21 45 service number 21 lasted 45 min.
6 28 service number 6 lasted 28 min.
etc..
The company can handle up to 25 different kinds of services. The input file is one month of data.
You are to count the number of service calls for each type of service handle and the number of minutes the call took.
The report should have in it the following information.
The report should have a title and headings.
Output for each type of service call rendered,
the total number of that service call handle for the month,
the total number of minutes spent on that type of service call,
the total number of service calls handle by the company,
the average number of minutes each service type took to handle,
the overall average a service calls took for the month.
I also need to know if and which service call types were not used.
Also tell me which service call took the most time to handle.
Label all output and make it a nice readable report, table format.
You must use arrays, pass arrays, and use functions.
Code
#include "stdafx.h"
#include<iostream>
#include<fstream>
using namespace std;
const int ROWS= 25;
const int COLS = 2;
double input;
ofstream OutFile;
//function prototype
void ReadFile(int[ROWS][2]);
void printArray(int[ROWS][2]);
int main()
{
int ary[ROWS][2];
//open-creates file to print to
OutFile.open ("ServiceCallOutFile.txt");
// Title and Heading
OutFile << "\nMy\n";
OutFile << "\nMonthly Service Call Report \n";
OutFile << "Service call report generated for September 2013\n\n";
cout << "\nMy \n";
cout << "\nMonthly Service Call Report \n";
cout << "Service call reprot generated for Oct. \n\n";
// Call Function 1
ReadFile(ary);
// Call Function 2
printArray(ary);
OutFile<<"\n-----------------------------"<<endl;
cout<<"\n-----------------------------"<<endl;
//closes .txt file
OutFile.close();
cin.get();
cin.get();
return 0;
}
// 1) Open and ReadFile .txt file for array
void ReadFile(int ary[ROWS][2])
{
ifstream infile("ServiceCalls.txt");
for(ROWS;ROWS<25;ROWS+1)
{
cout<<ary[ROWS][COLS];
for (COLS;ROWS<2;COLS+1)
{
infile>>ary[ROWS][COLS];
}
}
infile.close();
}
// 2) Print out all the values in the array with no more than 10 numbers per output line.
void printArray(int ary[ROWS][2])
{
OutFile<< "The numbers in the array are: \n";
cout<< "The numbers in the array are: \n";
for(ROWS;ROWS<25;ROWS+1)
{
cout<<ary[ROWS][COLS];
for (COLS;ROWS<2;COLS+1)
{
OutFile<<ary[ROWS][COLS]<<" "" ";
OutFile<<endl;
cout<<ary[ROWS][COLS]<<" "" ";
cout<<endl;
}
}
}
Input numbers from my .txt file.
17 47
10 43
20 30
4 34
15 22
21 20
3 48
17 38
18 37
12 12
5 5
4 14
8 35
17 29
21 46
2 17
You need to have something changing in the loop to actually execute it. You just used the constants you need for the boundaries and harded coded the constant values which is a Bad Idea. The general form of a for-loop is
for (initialization; condition; advance)
where the initialization can involve the definition of a value. For example, to iterate over the values 0 to 9, you could use the loop
int const boundary(10);
for (int i(0); i != boundary; ++i) {
...
}
Also, your code didn't make any check if your stream is in a good state: you should always check that a value was was actually successfully read from a stream. For example:
if (file >> value) {
use(value);
}
else {
std::cout << "ERROR: failed to read a value from the file\n";
}