I have an assignment in my C++ course to get information from a text file that says this:
Scores.txt
PhredrickTheGreat 5.7 5.3 5.1 5.0 4.7 4.8
RobbieTheRock 3.1 4.9 4.1 3.7 4.6 3.9
CannonBallKelly 4.1 5.3 4.9 4.4 3.9 5.4
MartyTheMissile 5.1 5.7 5.6 5.5 4.4 5.3
BillieBomb 5.9 4.8 5.5 5.0 5.7 5.7
JackKnifeJake 5.1 4.7 4.1 3.1 4.6 5.0
Splash 5.1 5.1 4.9 3.4 5.5 5.3
MillyTheMalard 4.9 4.3 5.2 4.5 4.6 4.9
HoraceTheDivingHorse 6.0 6.0 5.7 5.8 5.9 5.9
FishTank 4.3 5.2 5.9 5.3 4.3 6.0
These are the names of fictional baseball players (and batting scores?). The program should output the names of the players, their average score, and then assign them 1st, 2nd, 3rd, etc. place based on their average score. Here's what I have so far:
I commented out a couple of "couts," so you can ignore those.
#include <iostream>
#include <iomanip>
#include <fstream>
using namespace std;
struct Scores
{
float Score;
string Name;
};
float calculateAverage(float RawData){ return RawData / 6.0;}
int main()
{
string Name;
string Score;
float RawScores = 0;
float Average;
Scores ComScores[10];
ifstream playerData("Scores.txt");
for(int i = 0; i < 10; i++)
{
playerData >> Name; // Read in a name
//cout << left << setw(25) << Name << " ";
ComScores[i].Name = Name;
for(int j = 0; j < 6; j++) // Read in Six Scores
{
playerData >> Score;
RawScores += atof(Score.c_str());
//cout << Score << " ";
}
Average = calculateAverage(RawScores);
ComScores[i].Score = Average;
RawScores = 0;
//cout << " Ave: " << fixed << setprecision(2) << Average <<endl;
}
cout << "Place Name Score\n";
cout << "-------------------------------------\n";
for(int i=0; i < 10; i++)
{
if (i < 9){
cout << " " << i+1 << " " << setw(25) << ComScores[i].Name << " " << setw(8) << ComScores[i].Score << endl;
}
else{cout << i+1 << " " << setw(25) << ComScores[i].Name << " " << setw(8) << ComScores[i].Score << endl;}
}
cout << "\n";
cin.get();
return 0;
}
As you can see, I'm almost done I just have to order the places with qsort. My professor gave us one example of using qsort (which I can post), but it didn't really relate to this program (in my point of view). The programs already kinda big and complicated to a novice like me, so, I'm having trouble implementing qsort.
What can I add to my program to sort the last "for loop" to order the list?
I will answer any questions asap.
Here is a way you could do the comparison function :
int score_cmp(const void* a, const void* b)
{
const Scores* sa = (const Scores*)a;
const Scores* sb = (const Scores*)b;
if (sa->Score > sb->Score)
return -1;
else if (sb->Score > sa->Score)
return 1;
else
return 0;
}
And you would call qsort like this:
qsort((void*)ComScores, 10, sizeof(Scores), score_cmp);
That said, you should try to rewrite it yourself once you understand how it's supposed to work, it's not very hard and it's a good exercise.
But note that as #PaulMcKenzie pointed out, calling qsort with a non-trivial type is undefined behavior.
If you must use qsort, a simple but fairly ugly fix would be to replace the string member in struct Scores by a string* and then update the remaining code as needed (the qsort part would not have to change).
Related
I keep gettin this error on my code. My program was running perfectly just a few minutes ago and all of a sudden it kept throwing this error at me. I tried to find the error by using cout << "here" << endl in between some lines and sometimes it usually stops within my for loop inside the readInName() functions. Sometimes it would fully run and print out everything even the "here". Other times i would just get the same error.
#include <fstream>
#include <string>
using namespace std;
// global variables
// these must be changed depending on the file.
const int SIZE = 10; // num of students
const int AMOUNTOFGRADES = 5; // num of tests per student
ifstream input;
// function declarations
void readInName();
float calculateAvgAndGrade(int count);
void header();
int readInGrades(int);
int main(){
header();
readInName();
return 0;
}
void readInName(){
string name[SIZE] = {""};
input.open("grade.txt");
int row,column;
int count;
for(row = 0; row < SIZE; row++){
input >> name[row];
cout << setw(10) << name[row] << ": ";
count = readInGrades(row);
cout << setw(5) << calculateAvgAndGrade(count) << endl;
}
input.close();
}
int readInGrades(int){
int r,c;
int grades[SIZE][AMOUNTOFGRADES] = {0};
int count = 0;
for(c = 0; c < AMOUNTOFGRADES; c++){
input >> grades[r][c];
cout << setw(5) << grades[r][c] << " ";
count = count + grades[r][c];
}
return count;
}
float calculateAvgAndGrade(int count){
return float(count)/AMOUNTOFGRADES;
}
void header(){
cout << setw(15) << " Names " << setw(20) << "Grades " << setw(18) << "Avg " << endl;
cout << setfill('-') << setw(53) << '-' << endl << setfill(' ');
}
In readInGrades(), r is used uninitialized as an index to write into grades[r][c], which is undefined behavior. So r may by chance have any value and write to arbitrary locations in memory. This would sometimes corrupt the stack and trigger a segmentation fault. A helpful tool to troubleshoot these kinds of errors is AddressSanitizer, enabled in clang or gcc by compiling with -fsanitize=address, or if you are using Xcode, there is an option for it. Another great tool is valgrind.
In my opinion:
input >> grades[r][c];
r - isn't initialized.
So I have a loop that takes a line of formatted input that has a name and several numbers and it performs an operation to determine the total score based on those numbers. At the end of the program it is supposed to output the highest score as well as the name of the person who achieved the score. I have a count variable that increases each time it goes through the loop to score the number of the previous "total score" into an array. At the end of the program that array with all the totals is sorted from highest to lowest and then scoretotals[0] is outputted to display the highest score. My question is what is the easiest way to get the name corresponding to that number into a value that can be outputted at the end?
I have tried making a struct and then making that array part of the struct but this brings a lot of errors. So here is my code without attempts to output the name corresponding to the highest score
#include <iostream>
#include <cmath>
#include <string>
#include <fstream>
#include <algorithm>
#include <functional>
#include <iomanip>
using namespace std;
int main()
{
cout << "Name " << "Diff " << "Sorted scores " << "Total" << endl;
struct contestants
{
string name;
double difficulty;
double score1;
double score2;
double score3;
double score4;
double score5;
double score6;
double score7;
double score8;
double score9;
};
contestants person;
ifstream divers ("m6dive.txt");
int count = 0;
double scoretotals[50];
while (divers >> person.name >> person.difficulty >> person.score1 >> person.score2 >> person.score3 >> person.score4 >> person.score5 >> person.score6 >> person.score7 >> person.score8 >> person.score9)
{
double scores[9] = { person.score1, person.score2, person.score3, person.score4, person.score5, person.score6, person.score7, person.score8, person.score9 };
std::sort(scores, scores + 9, std::greater< double >()); //sorts from max to min
double total = (scores[1] + scores[2] + scores[3] + scores[4] + scores[5] + scores[6] + scores[7]) * person.difficulty; //computes score (total excluding min,max multiplied by score)
//outputs name, difficulty, scores sorted and total
cout << person.name << "\t" << std::setprecision(1) << fixed << person.difficulty << "\t" << scores[8] << "\t" << "\t" << scores [7] << " "<< scores [6] << " " << scores[5] << " " << scores[4] << " " << scores [3] << " " << scores [2] << " " <<scores[1] << " " << scores [0] << " " << total << endl;
scoretotals[count] = total;
count++;
}
std::sort(scoretotals, scoretotals + 50, std::greater< double >());
cout << "Highest score is " << scoretotals[0];
}
Output:
Name Diff Sorted scores Total
Anne 2.0 8.0 8.0 8.5 8.5 9.0 9.0 9.0 9.5 9.5 123.0
Sarah 3.0 8.5 8.5 8.5 8.5 9.0 9.0 9.0 9.5 9.5 186.0
Jon 1.5 6.0 7.0 7.5 7.5 7.5 8.0 8.5 8.5 8.5 81.8
Highest score is 186.0
. . .
Instead of storing and sorting scoretotals, store and sort contestant's!!
If you add a function for calculating <, you can call sort() with your own struct!
struct less_than_key {
inline bool operator() (const contestant& c1, const contestant& c2)
{
//Consider making a different function to calculate totals to simplify this copy/paste!
double c1_total = (c1.score1 + ... + c1.score9) * c1.difficulty;
double c2_total = (c2.score1 + ... + c2.score9) * c2.difficulty;
return (c1_total < c2_total);
}
};
And then you can sort with:
std::sort(people, people + 50, less_than_key());
After that, it'd be as simple as pulling out the first person and grabbing their name and total!
I'm struggling getting my columns to align on an assignment I have for school. The directions are to ensure that each column heading aligns correctly with its respective column. I've tried everything I've found online so far, including the cout.width() and the setw(), neither of which has worked. I'm hoping it's not due to me implementing these methods incorrectly, though I can't think of any other reason why they wouldn't work. The assignment specifically has 2 student names to use as an example. Jones, Bob and Washington, George. Due to the major difference in the number of characters between one student and the next, the columns just won't align. I know that setting a column width should fix that, but in my case it isn't. Then code I'm supplying is using the setw() method, but I can supply how I tried using the cout.width() if needed. Any help is GREATLY appreciated.
#include <iostream>
#include <iomanip>
#include <string>
#include <cstdlib>
using std::cout;
using std::cin;
using namespace std;
const int ARRAYSIZE = 2;
struct studentData{
string lastName;
string firstName;
float studentGpa;
}studentArray[ARRAYSIZE];
void displayData(int a);
int main()
{
int counter = 0;
for (int a = 0; a < ARRAYSIZE; a++)
{
cout << "Enter last name: " << endl;
cin >> studentArray[a].lastName;
cout << "Enter first name: " << endl;
cin >> studentArray[a].firstName;
cout << "Enter GPA: "<< endl;
cin >> studentArray[a].studentGpa;
counter++;
}
cout << "\n\n";
displayData(counter);
return 0;
}
void displayData(int a)
{
int newSize = a;
cout << left << setw(20) <<"\nName(Last, First)";
cout << right << setw(20) << "GPA\n";
for (int z = 0; z < newSize; z++)
{
cout << studentArray[z].lastName << ", " << studentArray[z].firstName;
cout << right << setw(20) << fixed << setprecision(2) <<studentArray[z].studentGpa << endl;
}
}
And my console input/output:
Enter last name:
Jones
Enter first name:
Bob
Enter GPA:
3.0
Enter last name:
Washington
Enter first name:
George
Enter GPA:
4.0
Name(Last, First) GPA
Jones, Bob 3.00
Washington, George 4.00
You are along the right lines, but std::setw only applies to the next output operation. If you turn printing the name into one operation, instead of 3 (last, comma, first) then you can pad the width of that more easily:
void displayData(std::size_t a)
{
std::cout << std::left
<< std::setw(20)
<< "Name(Last, First)"
<< "GPA\n";
for (std::size_t z = 0; z < a; ++z)
{
std::cout << std::left
<< std::setw(20)
<< (studentArray[z].lastName + ", " + studentArray[z].firstName)
<< std::fixed << std::setprecision(2)
<< studentArray[z].studentGpa
<< '\n';
}
}
Output:
Name(Last, First) GPA
Jones, Bob 3.00
Washington, George 4.00
Here, both for printing the column headings, and for the student names, I use std::left to say that the content should be at the left of the padded total, and std::setw to pad this output operation to 20 characters total (by default it will pad with spaces).
In both cases, this is the 1st column in the output, so I don't need to do anything with the 2nd column. If you had a 3rd column, you would need to pad the 2nd as well.
I also replaced your ints with size_ts for array indexing. It's a little point, but you shouldn't really use a signed type for indexing into a container where accessing a negative index would be Undefined Behaviour.
Also, please reconsider your use of what are often considered bad practices: using namespace std; and endl (those are links to explanations).
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
int d,m;
int districts=3;
int months = 12;
double sales[districts][months];
for (d=0 ; d < districts; d++)
{
for(m=0; m< months; m++)
{
cout << "Enter sales for District " << d+1 << ":" << " and Month " << m+1 << ": ";
cin >> sales[districts][months];
}
}
cout << "\n\n\n";
cout << setw(40) << "Months\n";
cout << setw(26) << "1 2 3 4 5 6 7 8 9 10 11 12\n";
for (d=0; d < districts ; d++)
{
cout << "District " << d+1;
for(m=0; m< months; m++)
{
cout << ": " << sales[districts][months];
}
}
return 0;
}
This code after running takes only two input values from user and after that a window appear displaying message a problem caused the program to stop working correctly.
There are no compilation errors and I am unable to find the problem. Is there anyone who can help?
You use variables d and m as counter-variables for your loops, but inside the loops you use the maximum value for both of them (districts and months) instead of d and m.
Change this: cin >> sales[districts][months]; to this: cin >> sales[d][m];
Also, this: cout << ": " << sales[districts][months]; to this: cout << ": " << sales[d][m];.
The term sales[districts][months] refers to a particular element sales[3][12], which also happens to be out of bounds for the 2-d array.
The reading loop is repeatedly reading a value to sales[districts][months], i.e. to sales[3][12], which - since array indexing starts at zero in all dimensions, doesn't exist. That gives undefined behaviour.
The output loops are repeatedly outputting the same value, which also gives undefined behaviour.
A common symptom (but not the only possible one) of undefined behaviour is abnormal program termination - and you are seeing an example of that.
There is also the wrinkle that
int districts=3;
int months = 12;
double sales[districts][months];
involves a variable length array (VLA) which is a feature of C (from the 1999 C standard or later) but is not valid C++. If that construct works for you, your compiler supports a non-standard extension.
I'm working on an app that needs to print an array through cout on one line, and show 2 decimal places. Currently, my code prints the first two items with 2 decimals, then switches to 1.
Here is the code:
cout << " Inches ";
cout << showpoint << setprecision(2) << right;
for (int i = 0; i < 12; i++)
{
cout << setw(5) << precipitation[i];
}
cout << endl;
And here is the output:
Inches 0.72 0.89 2.0 3.0 4.8 4.2 2.8 3.8 2.7 2.1 1.6 1.0
Can someone please tell me why this change is precision is occurring and what I can do to fix it?
Thanks
You need to use "fixed" mode. In default floating-point mode, precision() sets the number of significant figures to display. In "fixed" mode, it sets the number of places after the decimal. Case in point:
#include <iostream>
using namespace std;
int main(int argc, char **argv) {
float pi = 3.14;
cout.precision(2);
cout << pi << endl;
cout << fixed << pi << endl;
}
Gives the output:
3.1
3.14
HTH.
If you just add cout << fixed before output statements in addition to showpoint and setprecision, you will get a consistent formatting for all outputs.
See below:
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
double precipitation[12] = { .72, .89, 2, 3, 4.8, 4.2, 2.8, 3.8, 2.7, 2.1, 1.6, 1 };
cout << " Inches ";
cout << showpoint << fixed << setprecision(2) << right;
for (int i = 0; i < 12; i++)
{
cout << setw(5) << precipitation[i];
}
cout << endl;
return 0;
}
Now, the output will be as bellow:
Inches 0.72 0.89 2.00 3.00 4.80 4.20 2.80 3.80 2.70 2.10 1.60 1.00
I was troubled with this problem too. You need to use 'fixed' to do this.
Refer to this link:
C++ setprecision(2) printing one decimal?