grading test

Hello I need help with this program. I am having a problem getting my lowest and highest score to be omitted and only listing the other eighteen as used.
I am lost can anyone help?





#include <iostream>
#include<iomanip>
#include<ctime>
#include<cstdlib>
#include <string>
using namespace std;
const int NUMBER_OF_GRADES = 20;
char LetterGrade(int testScore)
{
if (testScore >= 90)
return 'A';
else if (testScore >= 80 && testScore < 90)
return 'B';
else if (testScore >= 70 && testScore < 80)
return 'C';
else if (testScore >= 60 && testScore < 70)
return 'D';
else if (testScore < 60)
return 'F';
}
int sum(const int TestScores[], int ArraySize, int& IndexHighestScore, int& IndexLowestScore)
{
int indexOfHighest = 0;
int indexOfLowest = 0;
int valueOfHighest = TestScores[0];
int valueOfLowest = TestScores[0];

for (int i = 1; i < ArraySize; i++)
{
if (TestScores[i] > valueOfHighest)
{
valueOfHighest = TestScores[i];
indexOfHighest = i;
}


if (TestScores[i] < valueOfLowest)
{
valueOfLowest = TestScores[i];
indexOfLowest = i;
}
}
return indexOfLowest;
return indexOfHighest;
}

void createScores(int TestScores[])
{
srand(time(0));
for (int i = 0; i < NUMBER_OF_GRADES; i++)
{
TestScores[i] = static_cast<int>(50 + rand() % 50);
}

}
//display 20 test scores, between 50 to 100
void displayScores(int TestScores[])
{
for (int i = 0; i < NUMBER_OF_GRADES; i++)
{
if ((i + 1) % 20 == 0)
cout << TestScores[i] << " " << endl;
else
cout << TestScores[i] << " ";
}

}
void displayStudentScores(int TestScores[], int ArraySize, int& IndexHighestScore, int& IndexLowestScore)
{

for (int i = 0; i < ArraySize; i++)
{
cout << setw(2) << i << setw(8) << TestScores[i] << setw(7) << LetterGrade(TestScores[i]);
if (i == IndexHighestScore || i == IndexLowestScore)
{
cout << setw(14) << "Omitted";
}
else {
cout << setw(11) << "Used";
}

cout << endl;
}

}


int main()
{
//test 20 random test scores
cout << "20 Randomly generated test scores: ";
//cin.ignore();
int TestScores[NUMBER_OF_GRADES];
createScores(TestScores);
displayScores(TestScores);

//calling the functions
int indexOfHighest;
int indexOfLowest;

//Test overload function
//test highest and the lowest score to omitted
cout << " Array information \n";
cout << "Index Score Grade Status \n";
cout << "------------------------------------\n";
int value = sum (TestScores, NUMBER_OF_GRADES, indexOfHighest, indexOfLowest);
displayStudentScores(TestScores, NUMBER_OF_GRADES, indexOfHighest, indexOfLowest);
cout << "------------------------------------" << endl;

return 0;
}
You are struggling a little with how the language works and some conceptual ideas.

First, I hope you are actually using proper indentation. This will help you significantly.

Call srand(time(0)); first thing in main() -- it should not appear in any function.


names int indexOfHighest; does not call any function. All it does is declare an integer variable. Part of what is hurting you is not being exact about what is going on with a given line of code. If you are unclear or mistaken about what a thing is doing then it will be impossible to reason about it.

// calling the functions
This is both vague and incorrect. Be specific. Improvement:
1
2
3
4
  // These two will be the indices of the largest and smallest 
  // values in the TestScores[] array, respectively.
  int indexOfHighest;
  int indexOfLowest;


//Test overload function
You aren't overloading any functions. You also are not testing anything. Improvement:
 
  // Find the indices of the largest and smallest values in TestScores[]. 


sum
This name says you are adding something. But you are not.
You are actually finding the indices of the largest and smallest values in TestScores[].
Find a better name for your function. The more obvious and droll the better:
1
2
3
4
5
find_index_of_largest_and_smallest
find_largest_and_smallest
get_indices_of_max_and_min
get_max_and_min
// and so on 



functions
The purpose of a function is one or both of:
  1. Perform some action
  2. Obtain some value

Your 'sum' function attempts to return two values. You have already noticed that you are returning a value (named "value") that you are completely ignoring. This is a good clue that you don't need to return the value. Change the function to void.

(The values returned are returned via reference arguments, which is a completely separate mechanism for returning values.)

1
2
3
4
5
void get_largest_smallest_indexes(int TestScores[], int ArraySize, int& IndexHighestScore, int& IndexLowestScore)
{
  ...
  // no return statement
}

Then, in main(), you don't need to create a bogus variable:
1
2
  // Find the indices of the largest and smallest values in TestScores[]
  get_largest_smallest_indexes(TestScores, NUMBER_OF_GRADES, indexOfHighest, indexOfLowest);


Okay, so there is another purpose to a function:
  3. Not repeat common code

You have two completely different functions just to print the student scores. Unless this is a requirement for your homework, you really only need one. Combine them.
1
2
3
4
5
6
7
8
9
10
11
  // Create our random collection of student grades and display what we have
  createScores(TestScores, NUMBER_OF_GRADES);
  displayScores(TestScores, NUMBER_OF_GRADES, -1, -1);

  ...

  // Find the indices of the largest and smallest values in TestScores[]
  get_largest_smallest_indexes(TestScores, NUMBER_OF_GRADES, indexOfHighest, indexOfLowest);

  // Display every score except the two we found
  displayScores(TestScores, NUMBER_OF_GRADES, indexOfHighest, indexOfLowest);

Notice also that the create and display functions no longer use the global value NUMBER_OF_GRADES -- instead they take the number of grades as argument.


keep related things together
It is easy to mix I/O in with everything, but this just makes life a headache.

You have a function that is designed to display scores -- it's whole purpose is to generate an output table.

Yet, you have the stuff that displays the header to that table somewhere else (in main()). Why is that?

Keep related stuff together.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void displayScores(int scores[], int nscores, int ignoreIndex1, int ignoreIndex2)
{
  cout << "Student Scores\n";
  cout << "Index Score Grade Status\n";
  cout << "------------------------------------\n";
  for (int i = 0; i < nscores; i++)
  {
    cout << setw( 6 ) << left << i;
    cout << setw( 6 ) << left << scores[i];
    cout << setw( 6 ) << left << LetterGrade(scores[i]);
    if (i == ignoreIndex1 || i == ignoreIndex2)
    {
      cout << "Omitted\n";
    }
    else
    {
      cout << "Used\n";
    }
  }
  cout << "------------------------------------\n";
}

The setw() manipulator is designed to provide a minimum number of characters output. Notice how I adjusted the code to line things up under the header.

Also notice how I changed the argument names. I did that on purpose to point out that formal arguments are different things than the actual arguments supplied to a function -- name means nothing except a hint to the human programmer as to what the thing represents.

I could have two arrays. One for grades from class A and one from class B. But I can reuse the functions for either array.

1
2
3
4
5
6
7
8
9
  int classAScores[NUMBER_OF_GRADES];
  int classBScores[NUMBER_OF_GRADES];
  ...

  cout << "Class A\n";
  displayScores(classAScores, NUMBER_OF_GRADES, -1, -1);

  cout << "Class B\n";
  displayScores(classBScores, NUMBER_OF_GRADES, -1, -1);



final notes
You are otherwise doing pretty well for a start. The basic design of your "find index of largest & smallest" and print functions are pretty good.

Well, that's enough from me. Hope this helps.
Thanks for the input Duthomhas (10640) here are the originals instructions for this project, I did what I could before turning it in.
1) Write a program that randomly generates 20 test scores, between 50 to 100, and store them into an int array.

2) Include two overloaded functions with the following headers and requirements:
a. Headers:
double sum(const double TestScores[], int ArraySize, int& IndexHighestScore, int& IndexLowestScore)
int sum(const int TestScores[], int ArraySize, int& IndexHighestScore, int& IndexLowestScore)
b. Requirements:
i. Reject outliers: the highest and the lowest score are omitted. Therefore, only 18 scores are to be sum and be used in finding the average score.
ii. These functions will retain of the indices (pass by reference) of the highest and lowest scores in the array.

3) Include two overloaded functions that return a letter grade of a score with the following headers and requirements:

a. Headers:
char LetterGrade( int testScore)
char LetterGrade( double testScore)
b. Requirements:
Determine and return the letter grade base on the test score (pass by value) as follow:
testScore >= 90, LetterGrade is ‘A’
testScore >= 80 and < 90, LetterGrade is ‘B’
testScore >= 70 and < 80, LetterGrade is ‘C’
testScore >= 60 and < 70, LetterGrade is ‘D’
testScore < 60, LetterGrade is ‘F’

4) Test the functions from the main() and display the exact output as follow:


Those instructions are not entirely clear, but it looks like you are being asked to write a function "sum" that does more than one thing:

  - compute the sum of all values in the argument array except for the highest and lowest.
  - return the indices of the highest and lowest values in the array via reference argument
    (this is not entirely clear, but methinks it is the most likely interpretation)
  - It is also unclear how to handle multiple elements having max or min value.

In any case, the function should then return the sum of the added elements, which is what you need in order to compute an average (average = sum(elts) / number_of_elts)


You were asked to write two versions of this 'sum' function: one that takes an array of double and one that takes an array of int.

The instructions appear to only want you to generate one single array of int and compile against that.

This is how I would have coded it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include <ciso646>
#include <cstdlib>
#include <ctime>
#include <iostream>

double sum(const double TestScores[], int ArraySize, int& IndexHighestScore, int& IndexLowestScore)
{
  // This function won't be called. If it is, we'll know it, because its result is zero
  IndexHighestScore = IndexLowestScore = 0;
  return 0.0;
}

int sum(const int TestScores[], int ArraySize, int& IndexHighestScore, int& IndexLowestScore)
{
  int sum = 0;
  
  if (ArraySize <= 0) return 0;
  IndexHighestScore = IndexLowestScore = 0;
  
  for (int n = 0; n < ArraySize; n++)
  {
    if (TestScores[n] > TestScores[IndexHighestScore]) IndexHighestScore = n;
    if (TestScores[n] < TestScores[IndexLowestScore])  IndexLowestScore  = n;
    sum += TestScores[n];
  }
  
  return sum - TestScores[IndexHighestScore] - TestScores[IndexLowestScore];
}

int rand_score()
{
  // "Unbiased" random number in [50,100] inclusive.
  // (Sadly, it is still biased because rand() is crap.)
  while (true)
  {
    int x = rand();
    if (50 <= x and x <= 100) 
      return x;
  }
}

void generate_test_scores( int scores[], int n )
{
  while (n--) scores[n] = rand_score();
}

int main()
{
  srand(time(0));
  
  constexpr int NScores = 20;
  int scores[NScores];
  generate_test_scores( scores, NScores );
  
  int index_max, index_min;
  double average = sum( scores, NScores, index_max, index_min ) / (double)(NScores - 2);

  ...

Without the rest of the assignment you can still see the generated average and the "outlier" scores:
1
2
3
4
5
  for (int x : scores) std::cout << x << " "; std::cout << "\n";
  std::cout
    << "average = " << average
    << ", max score = " << scores[index_max]
    << ", min score = " << scores[index_min] << "\n";

You could also verify that the overloaded takes-array-of-double function gets called only with an array of double:
1
2
3
4
5
6
  double scores2[NScores];
  for (int n = 0; n < NScores; n++) scores2[n] = scores[n];

  double average2 = sum( scores2, NScores, index_max, index_min ) / (double)(NScores - 2);
  if (average2 == 0.0) std::cout << "Success\n";
  else                 std::cout << "Can't happen.\n";

Considering the deficiencies of the instructions, I probably would have lost some points here.

Anyway...
Topic archived. No new replies allowed.