C++ Test Score Code Help With Sorting and Arrays

Hi. This is my first time writing something on this website, and I am just really confused with my overall code.

So far it works, but my only issue is adding an array + sorting system to sort the ascending order of students' test scores.

For example, if the user decides to input 3 test scores, (anywhere from 0-100), then 3 test scores will appear on the screen, and correspond to the students's number.

Example:

" How many test scores would you like to enter?: 3

Student 1's test score is: 67
Student 2's test score is: 56
Student 3's test score is: 89

The test scores for 3 students have been recorded.

Student 1's test score is 67 percent
Student 2's test score is 56 percent
Student 3's test score is 89 percent "


Now, the code works fine up to this point because there's no array or sorting involved. But what if I want to include a sort function that sorts all of the students scores from least to greatest.

For example, how do I get the code to say:

" The scores between the 3 students in ascending order are: 56, 67, 89 "

I have pasted my code below if anyone is willing to help me for the last part. I have been extremely stressed, I don't know what to do, and I'm worried. Please help! ):


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
#include <iostream>
#include <bits/stdc++.h>
using namespace std; 

int main (){

//the # of scores that are entered by each student
int testAmount;
//scoreValue is the score value
int scoreValue; // 2 elements in 2 columns
//double represent fractions or decimal values. This way test scores can be in decimal form.
double** scoresArray = new double* [testAmount];

cout << "\nHow many tests scores would you like to input: ";
cin >> testAmount;

//loop to calculate the number of times (depending on the amount of test scores) the data will print out the test scores.
for (int i  = 0; i < testAmount; i++){
  scoresArray [i] = new double [scoreValue];
  scoresArray [i][1] = i + 1; // i + 1 is written so that counting the # of students start from 1 and not 0. 

  cout << "\nEnter the test score for student " << i + 1 << ": ";
  cin >> scoresArray [i][0]; //calculates test scores for each student.

//while loop to correct the user if no value between 0-100 is inputted. Until the user puts a number between 0-100, the loop will not end.
while (scoresArray [i][0] > 100 || scoresArray [i][0] < 0){

    cout << "\nInvalid entry\n";
    cout << "Input test score for student " << i + 1 << " again: ";
    cin >> scoresArray [i][0];
}
}
//prints out the test scores for each student
cout << "\nThe tests scores for " << testAmount << " students have been recorded: \n";
for (int i = 0; i < testAmount; i ++){
  cout << "\nStudent " << scoresArray [i][1] << "'s test score is \t";
  cout << scoresArray [i][0] << " %" << endl;
}
}

Last edited on
Hello allisonOs,

It is time for me to restart my computer, but while I wait>


PLEASE ALWAYS USE CODE TAGS (the <> formatting button), to the right of this box, when posting code.

Along with the proper indenting it makes it easier to read your code and also easier to respond to your post.

http://www.cplusplus.com/articles/jEywvCM9/
http://www.cplusplus.com/articles/z13hAqkS/

Hint: You can edit your post, highlight your code and press the <> formatting button. This will not automatically indent your code. That part is up to you.

You can use the preview button at the bottom to see how it looks.

I found the second link to be the most help.


Andy
Hello allisonOs,

You should compile the code before you post it. This way you will have the oppertunity to fix any errors or post the complete error message of any you do not understand.

Looking at your code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
//#include <bits/stdc++.h>  // <--- Not a standard C++ header file. It may include more header files than you need.

using namespace std;

int main()
{
    //the # of scores that are entered by each student
    int testAmount;       // <--- Not the best name. And the comment above does not describe well what it is used for.
    int numOfStudents{};  // <--- This would be the rows of the array.
    int numOfScores{};    // <--- This would be the columns of the array.

    //scoreValue is the score value
    int scoreValue; // 2 elements in 2 columns <--- Not the best name and kind of misleading.

    //double represent fractions or decimal values. This way test scores can be in decimal form.
    double** scoresArray = new double*[testAmount];

    cout << "\nHow many tests scores would you like to input: ";
    cin >> testAmount;

If you had compiled the code it should have complained the "testAmount" is an uninitialized variable that you are trying to make an array of. As an example an uninitialized "int" on my computer is usually "-858993460". Evan with dynamic memory for an array you can not use a negative number or (0) zero for the size.

It is ALWAYS a good to initialize your variables when defined. If for no other reason than to know that they do not contain a garbage value.

The next problem is that line 17 is trying to use a variable, "testAmount", that has yet to receive a proper value.

The next problem when the program runs id that line 17 and the for loop that follows uses "new" to create memory. When using "new" you MUST use "delete" to free the memory when you are finished with it. Most often this is done just before the losing } of "main".

Lines 10 and 11 are suggestions of variable names that make more sense. With line 10 being the replacement for line 9.

Before you can use any of the variables, (lines 9, 10 or 11), you need to give them a value that can be used when you use the "new".

Lines 17 and 20. These 2 lines do not work in reverse. You can not use the variable "testAmount" and then give it a value.

Until I get a proper "delete" I will not attempt to run the program because you have a memory leak. This memory may or may not be freed when the program ends. You need to make sure it is.

Andy
I have run the program up to the point of creating memory and the initial screen looks like:

             A possible heading
--------------------------------------------
 How many students will you have?: 3

 How many grades does each student have?: 3


Now when you use "new" the variables will have a proper value.

Andy
Hi Andy,

Thanks for the feedback. I have a fixed my code according to what you've mentioned. Also, my apologies for the formatting of the code as this is my first time using this website to ask a question.

I would just like to point out that testAmount (numOfStudents) on line 17 does not have an exact value because it's the value the user should input.

Line 17 creates a 1D array for the rows (numOfStudents) before introducing the number of columns, (the numOfScores) to create the 2D array.

Since the numOfScores should always be 2 (for 2 columns), I have initialized it to be 2: ' numOfScores = 2 ' but I'm not sure how I can assign a value to numOfStudents if that can vary.

My goal is to sort the scores inputted for each student, scoresArray [i][0] in ascending order. If (0) is not acceptable for the size, what other variable can I use?

I am aware you can do this using regular integers, but how can we rearrange the order from the user's input?

Here is an updated version of my code if you're willing to look at it once more. Thank you again.

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
#include <iostream>
using namespace std;

int main(){

int numOfStudents; // # of rows going down
int numOfScores = 2; //2 columns

cout << "\nHow many test scores would you like to input: ";
cin >> numOfStudents;

//represents fractions or decimal values. This way test scores can be in decimal form.
double** scoresArray = new double* [numOfStudents];
//loop to calculate the number of times (depending on the amount of students) the data will print out the test scores.
for (int i = 0; i < numOfStudents; i++){
  scoresArray [i] = new double [numOfScores];
  scoresArray [i][1] = i + 1; // i + 1 is written so that counting the # of students start from 1 and not 0. 

  cout << "\nEnter the test score for student " << scoresArray [i][1] << ": ";
  cin >> scoresArray [i][0]; //calculates test scores for each student.

//while loop to correct the user if no value between 0-100 is inputted. Until the user puts a number between 0-100, the loop will not end.
while (scoresArray [i][0] > 100 || scoresArray [i][0] < 0){

    cout << "\nInvalid entry\n";
    cout << "Input test score for student " << i + 1 << " again: ";
    cin >> scoresArray [i][0];
}
}
//prints out the test scores for each student
cout << "\nThe tests scores for " << numOfStudents << " students have been recorded: \n";
for (int i = 0; i < numOfStudents; i++){
  cout << "\nStudent " << scoresArray [i][1] << "'s test score is \t";
  cout << scoresArray [i][0] << " %" << endl;
}
}
Last edited on
The reason I am doing this code is to complete a project assignment for my C++ class and my professor requests that we

Write a C++ program (with two arrays) that

Reads the student number (integer type) and the test scores (decimal number) from the keyboard and store the data in two separate arrays and provide a method to end that input. The arrays should provide a size of at least 50.

The program should also display the student's numbers (ex. Student 1, Student 2) and scores in a two column format, and the arrays should be sorted according to the test scores (aligned together)

What I'm missing is displaying the student numbers and scores in a two column format again, but this time the data is sorted from least to greatest (or ascending order).

Can you provide any more suggestions? Since the project isn't due until November 17th, I can simply restart and try it again, but since I've already met most of the criteria, I don't see why the code can't be modified to rearrange data, or the test scores: ' scoresArray [i][0] '
Last edited on
The assignment asks for 2 arrays - not 1 2d array. So consider:

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
#include <iostream>
#include <utility>
using namespace std;

void Sort(double* score, int* stud, int n)
{
	do {
		size_t newn {1};

		for (size_t i = 1; i < n; ++i)
			if (score[i - 1] > score[i]) {
				swap(score[i - 1], score[i]);
				swap(stud[i - 1], stud[newn = i]);
			}

		n = newn;
	} while (n > 1);
}

int main() {

	int numOfStudents {};

	cout << "How many test scores would you like to input: ";
	cin >> numOfStudents;

	double* scoresArray {new double [numOfStudents] {}};
	int* studArray {new int[numOfStudents] {}};

	for (int i = 0; i < numOfStudents; ++i) {
		studArray[i] = i + 1;

		while ((cout << "Enter the test score for student " << studArray[i] << ": ") && !(cin >> scoresArray[i]) || (scoresArray[i] > 100 || scoresArray[i] < 0)) {
			cout << "Invalid entry\n";
			cin.clear();
			cin.ignore(1000, '\n');
		}
	}

	Sort(scoresArray, studArray, numOfStudents);

	cout << "\nThe tests scores for " << numOfStudents << " students have been recorded: \n";

	for (int i = 0; i < numOfStudents; i++)
		cout << "Student " << studArray[i] << "'s test score is \t" << scoresArray[i] << " %\n";

	delete[] studArray;
	delete[] scoresArray;
}

Hello allisonOs,

Sorry for the delay. You posted after I went to bed.

Lets take a look at this:

Write a C++ program (with two arrays) that

Reads the student number (integer type) and the test scores (decimal number) from the keyboard and store
the data in two separate arrays and provide a method to end that input. The arrays should provide a size of at least 50.

The program should also display the student's numbers (ex. Student 1, Student 2) and scores in a two column
format, and the arrays should be sorted according to the test scores (aligned together)

What I'm missing is displaying the student numbers and scores in a two column format again, but this time
the data is sorted from least to greatest (or ascending order).


As seeplus mentioned The assignment asks for 2 arrays - not 1 2d array. And that is the way I read it too. No where in the above text dos it say to use a dynamic array, but that should make no difference. Just be sure to "delete" the memory when you are done using it. As seeplus has demonstrated at the end of his program.

I am taking the second paragraph to me the output that is displayed. That part is not difficult.

I came up with this as a possible start:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>

using namespace std;

int main()
{
    constexpr int MAXSIZE{ 50 };

    int studentID[MAXSIZE]{};          // <--- ID can be generated in a for loop.
    double scoresArray[MAXSIZE]{};  // <--- Needs to be entered in the for loop.

    int numOfStudents{};            // <--- The part of the array to be used. Not to exceed MAXSIZE.
    //int numOfScores = 2; //2 columns

    cout << "\nHow many test scores would you like to input: ";
    cin >> numOfStudents;

    // <--- A check that numOfStudents does not exceed MAXSIZE. 

Should you want or need to use a dynamic array you can. Start be deleting lines 9 and 10 and use:
1
2
double scoresArray = new double[MAXSIZE];
int  studentID = new int[MAXSIZE];
Because the directions say that the array should be able to hold a maximum of 50.
IMO creating a dynamic array of a fixed size tends to defeat the purpose of the dynamic array. Here a conventional C style array will work just fine.

Your for loop will need some adjustments, but for the most part it looks OK for now. Although I have not tested the while loop yet.

I would get this far first. Until you have 2 arrays with proper values to work with you have nothing to sort. Once you have the arrays correct the sort will become easier.

Andy
Hello allisonOs,

I forgot to ask if you have studied functions yet?

Andy
 
The arrays should provide a size of at least 50.


That doesn't make much sense. I would have understood if it said 'The arrays should provide a size of at most 50'. So if there are only 10 test scores to input, you still need to have arrays of size 50? No really. If you are going to input 60 test scores then you have arrays of size 60. I'd query this with your professor. So what this means is that the size of the arrays is max(50, numOfStudents)?? Does not compute.
Last edited on
Hi Andy,

No worries, I'm assuming we live in different time zones. Therefore, I apologize for a delayed response.

I just want to start off by thanking you for your help. You've explained the content well, and I've actually implemented most of your ideas. I will show you the finalized code below.

Also, thanks for pointing out that the assignment intended for 2 arrays and not a 2D array – we are still going over this chapter so I figured it would imply the same thing, hence the amount of code I wrote.

My class starts in about an hour so I will update you about the context behind
array size of at least 50.


I wasn't sure what he meant by this either, but I was assuming (before I started the assignment) he meant that the numOfStudents should hold up to 50 integers. I believe I have met that criteria already since you can input as many students, or test scores as possible. But again, I am not too sure.

We have reviewed and revisited functions and parameters every now and then. I mainly worked more with functions when I took computer science and used Java, so I'm not too familiar with the purpose it serves in C++ ( except int main() )

I like how you included a void function at the beginning of the code to actually sort out the scoreArray[i] data. That's exactly what I needed, and I attempted it before but it just went wrong, and instead of sorting the data correctly, it inputted data as "0.00" instead of the actual score that was input by the user. I believe I just had the formula written incorrectly.

Lastly, I just had a genuine question about a header file you used.
Why is the #include <utility> used above? Is it for the swap function to work properly? If so, I deleted it just to test it out, but it seemed to work fine with just the basic, #include <iostream> . I added it back to my final code regardless to avoid any potential errors.

Anyway, the finalized code is just below.
I have modified only a few things like the "while" loop you suggested. When I ran it, the program didn't reject any number greater than 100 and less than zero.
Since the user cannot input two values (like -1 or 101) at the same time for a student test score, I thought it made sense to just use an 'or' operator (instead of the && and operator) to make both conditions unacceptable, and therefore, keep "correcting" the user to input a number that ranges from 0-100 (if that makes sense).

It seemed to work afterwards. Let me know what you think:

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
59
60
#include <iostream>
#include <utility>
using namespace std;

void Sort(double* score, int* stud, int n)
{
	do {
		size_t newn {1};

		for (size_t i = 1; i < n; ++i)
			if (score[i - 1] > score[i]) {
				swap(score[i - 1], score[i]);
				swap(stud[i - 1], stud[newn = i]);
			}
		n = newn;
	} while (n > 1);
}

int main() {

	int numOfStudents;

	cout << "\nHow many test scores would you like to input: ";
	cin >> numOfStudents;

	double* scoresArray {new double [numOfStudents] {}};
	int* studArray {new int[numOfStudents] {}};

	for (int i = 0; i < numOfStudents; ++i) {
		studArray[i] = i + 1;

		cout << "Enter the test score for student " << studArray [i] << ": ";
  cin >> scoresArray [i]; //stores test scores for each student.

//Until the user enters a number between 0-100, the loop will not end.
while (scoresArray[i] > 100 || scoresArray [i] < 0){

    cout << "\nInvalid entry\n";
    cout << "Input test score for student " << i + 1 << " again: ";
    cin >> scoresArray [i];
}
		}
  cout << "\nThe test scores for " << numOfStudents << " students have been recorded: \n";
  for (int i = 0; i < numOfStudents; i++){
    cout << "Student " << studArray[i] << "'s test score is \t";
    cout << scoresArray [i] << " %" << endl;
  }

  Sort(scoresArray, studArray, numOfStudents);
  
	cout << "\nThe test scores for " << numOfStudents << " students have been sorted:\n";

	for (int i = 0; i < numOfStudents; i++)
		cout << "Student " << studArray[i] << "'s test score is \t" << scoresArray[i] << " %\n";


//delete operator to remove the memory from the program
	delete[] studArray;
	delete[] scoresArray;
	}




Last edited on
Update about
the array size of at least 50
:

My professor confirmed what I had written earlier.

He said he means that the array size should extend up to at least 50 students (therefore, you can input more than just 50 test scores as there is no limit).

Since our code can hold up to an infinite number of positive values, it doesn't matter.

The sample he had in mind after he assigned the task was:

Sample output:

Enter student’s number:

1

Enter student’s test score:

89

Do you have more students? (y/n)

y

Enter student’s number:

2

Enter student’s test score:

95

Do you have more students? (y/n)

y

Enter student’s number:

3

Enter student’s test score:

76

Do you have more students? (y/n)

n

You entered:

1             89

2             95

3             76

The list sorted by test scores:

3             76

1             89

2             95


which is why he intended for the y/n choice to reach up to at least 50.

But since we started off the code by asking the user to enter the number of test scores they will be using, there was no need for a choice loop like he sampled above (since the value for numOfStudents is already held). Hence, there is no need to meet that criteria if it can reach up to any number the user wants. Essentially, the number of students is dependent on the user.

Anyway, he even said that having an array of at least 50 is something he won't bother checking, especially if he has to input those 50 grades manually only to test if it works (it will take him a long time lol).

Hopefully this cleared up any confusion. Thank you so much, again.
Last edited on
Hello allisonOs,

Actually we are in the same time zone. Just Pennsylvania between us.

You are welcome. I am glad that you understand it better.

I am not sure about Java, but I would think that the concepts of a function is much like it is in C++.

In C++ a function is a way to break up the program into smaller pieces, (functions), that do 1 task. This is a way you keep from having the "main" function being 1000 lines or more. Later you will learn about putting functions in a separate ".cpp" file, so that the "main" file is not cluttered with code that it does not need right away.

Although I did have an idea of putting the sort in a function I was waiting to see if you know how to use them yet. The function you are referring to is from seeplus. A nice idea for the function, but I did it a bit differently.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
int tempInt{};
double tempDouble{};

for (int idx = 0; idx < numOfStudents - 1; idx++)
{
    for (int idxp1 = idx + 1; idxp1 < numOfStudents; idxp1++)
    {
        if (scoresArray[idx] > scoresArray[idxp1])
        {
            tempDouble = scoresArray[idx];
            tempInt = studentID[idx];

            scoresArray[idx] = scoresArray[idxp1];
            studentID[idx] = studentID[idxp1];

            scoresArray[idxp1] = tempDouble;
            studentID[idxp1] = tempInt;
        }
    }

    //std::cout << std::endl; // <--- Used as a break point for testing. Comment out delete when finished.
}

This code is used in "main", but I also put this in a function. Either way it works. This may not be as fancy as what seeplus did, but it should give you a better understanding of how it works.


Lastly, I just had a genuine question about a header file you used.
Why is the #include <utility> used above? Is it for the swap function to work properly? If so, I deleted it just to test it out, but it seemed to work fine with just the basic, #include <iostream> . I added it back to my final code regardless to avoid any potential errors.


Yes the "std::swap" is defined in <utilities> header file. According to cppreference.com "std::swap" is also defined in the <algorithm> and <string_view> header files. Choosing which header file to use, (<utilities> or <algorithm>) may depend on what else you may need to use in 1 of these header files or it may depend on what you want to avoid.

Not knowing what IDE/compiler you are using it is very possible that <iostream> may include a <utility> header file without you even knowing about it. It may also come from 1 of the other header files that are automatically included into your program.

As to the last part. Since different compilers use different it is a good practice to include a header file even if your compiler does not need it. Someone else might.

An example I can use the line
 
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');  // <--- Requires header file <limits>. 
without including the header file <limits> because <iostream> will include the header file <xlocnum> and in that it includes
1
2
3
4
5
#include <climits>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <streambuf> 

Which covers what I need for the ignore line, but it is still better to include the proper <limits> header file.

Again seelus has the more complex while loop. A good approach, but something you are not quite read for yet. This concept might be a little easier to understand:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
while (!std::cin || (scoresArray[i] > 100 || scoresArray[i] < 0))
{
    if (!std::cin)
    {
        std::cerr << "\n     Invalid Entry! Must be a number.\n\n";
        std::cin.clear();  // <--- Resets the streams' state bits.
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');  // <--- Requires header file <limits>. Clears the input buffer.
    }
    else if (scoresArray[i] > 100 || scoresArray[i] < 0)
    {
        cout << "\n     Invalid entry\n\n";
    }

    cout << "Input test score for student " << i + 1 << " again: ";
    cin >> scoresArray[i];
}

Using formatted input cin >> scoresArray[i]; cin is expecting a number to be entered. If not the stream fails and is unusable until it is fixed.

This version of the while loop will catch both problems and give you a change to understand seepluss' version.

The only warning I had when I compiled the had to do with using "size_t". The only guarantee is that "size_t" is an "unsigned something" The something is defined by the header files that you are using. This could be an "int" or a "long". Maybe even a "long long". The problem is in for (size_t i = 1; i < n; ++i). Here "i", an unsigned something, is being compared to a signed int. Not a big problem, but a potential problem. It should at least be a compiler warning of of a signed unsigned mismatch. In the for loop I changed "size_t" to an "int" and the warning went away.

Andy
Ah yes, I believe that functions in C++ work the same way they do in Java. Functions in Java are often referred to as "abstractions" as it incorporates repeated code into smaller pieces, just like you mentioned.

The compiler I used to write the code was Microsoft Visual Studio 2019. Therefore, I do believe that the <iostream> I mentioned does include a <utility> header file. Regardless, I kept both in the final code to make sure it's accessible to all people, like you said.

I tested out seepluss' version of the while loop and even though it seemed complicated at first sight, after implementing it into my code ( just to mess around with it and see how it works on my end ), it's pretty detailed. I like the idea of it rejecting a non-number, and not just any number that is less than zero or greater than 100. My final code doesn't do that. But as much as I like how this works and knowing this hasn't been reviewed yet, my professor would probably question how I came up with that kind of complex loop

All in all, I did learn from it as I experimented with it in my code so I thank you for showing me. It will definitely help in the future, and I can always refer back to this.

My only surprise is that there was no need for a "temporary holding variable" to temporarily hold the value of a test score when as they swapped places. But again, there are probably many different ways to sort an array, and since the goal is to compare each array element to another array element and swap them if they are in the wrong position, the code seemed to do just that without a 'temp' variable.

I can't thank you enough for all your help. Apparently I only have 2 or 3 of these assignments left in the semester, and so far I've aced all of them (until this one, and I actually had no idea where to start, or even how to finish it) but you've been of great help. Hopefully I ace the remaining two assignments. Have a great rest of your night. (:
Hello allisonOs,

I agree that my code with the "temp" variable may be old, but it is still a good learning tool to understand how it is done.

Andy
Topic archived. No new replies allowed.