Dynamically Allocating an array of structures

Pages: 123
Look at line 18. Where do you think you're storing those score values?

Also:

Look at line 8, and then at line 15. Then, look at line 18 and tell me what value you think i will contain?
Last edited on
from the looks of line 18 it looks like I am storing the values into the member testScores in the student struct, and from looking at line 8 , line 15, and line 18, it looks like its storing it into the index?
Should I change the index?
Look at this fragment that is in your code:
1
2
3
4
for ( int i = 0; i < NUM_TESTS; i++ )
{
    cin >> students[ i ].testScores[ NUM_TESTS ];
}

Lets pretend that the testScores[ NUM_TESTS ] is named attribute
The code looks like:
1
2
3
4
for ( int i = 0; i < NUM_TESTS; i++ )
{
    cin >> students[ i ].attribute;
}

What happens there?
* NUM_TESTS values are read from the user
* Each value is stored in attribute of a different student

That is all fine, as long as the array students has at least NUM_TESTS elements. Does it?


Lets not pretend any more.
A Student has member array testScores.
How many elements does that array have?
NUM_TESTS elements.

Is testScores[ NUM_TESTS ] an element in the array testScores? No.
The last element of the array is testScores[ NUM_TESTS - 1 ]

It is an out of range error to do:
1
2
Student john;
cin >> john.testScores[ NUM_TESTS ]; // ERROR 

You do that error NUM_TESTS times in that loop. If you call that loop more than once, then you repeat the error even more.

Furthermore, you never stored anything into any element of the array testScores. Why do you have an array that you don't use for anything?


Yes, you should know what indices you use.
That's the thing, I am attempting to store the scores in that array "testScores" with the fixed size known as NUM_TESTS. My goal is to have the Student struct including a fixed size testScores array that stores a list of four test scores for a group of students .
Last edited on
I added some debugging info to getInfo():
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
void getInfo(Student *ptr, int size)
{

    double index = 0;
    double index2 = 0;

    for(int i = 0; i < size; i++)
    {
        cout << "Student #" << index + 1 << " Name: ";
        cin >> ptr[i].name;
        cout << "ID Number: ";
        cin >> ptr[i].idNum;

        for(int i = 0; i < NUM_TESTS; i++)
        {
            cout << "student " << i << " test score #" << NUM_TESTS << '\n';
            cout << "      Test #" << index2 + 1 << ": ";
            cin >> ptr[i].testScores[NUM_TESTS];

            index2++;
        }

        index++;
    }

}

Lines 16 prints the exact indexes that it uses to store the test score at line 18 (i and NUM_TESTS). Now let's see what happens when we run it:
          Course Grade Program
========================================

How many students: 2

Student #1 Name: Dave
ID Number: 1234
student 0 test score #4
      Test #1: 88
student 1 test score #4
      Test #2: 84
student 2 test score #4
      Test #3: 85
student 3 test score #4
      Test #4: 92
Student #2 Name: Scottie
ID Number: 5678
student 0 test score #4
      Test #5: 92
student 1 test score #4
      Test #6: 93
student 2 test score #4
      Test #7: 94
student 3 test score #4
      Test #8: 95
------ Course Grade Report: --------------
Student Name: Dave
ID Number: 1234
Average Test Score: 2.50321e-308
Grade:
-------------------------------------------------
Student Name: Scottie
ID Number: 5678
Average Test Score: 6.79453e-313
Grade:
-------------------------------------------------

Look at the bolded lines. Clearly these indexes aren't what you want. Those two lines should be
student 0 test score #0
student 0 test score #1


The problem with the student number is subtle so I'll give you that one. Look at lines 7 and 14:
1
2
3
    for(int i = 0; i < size; i++)
...
        for(int i = 0; i < NUM_TESTS; i++)

Both looks use an index named i. In C++, these are separate variables with the same name. Inside the inner loop, i refers to the inner loop index, not the outer one.

The bug may be clearer if we use different names for the index numbers. Here is the code with the outer index called studentNum and the inner one called testNum
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
void getInfo(Student *ptr, int size)
{

    double index = 0;
    double index2 = 0;

    for(int studentNum = 0; studentNum < size; studentNum++)
    {
        cout << "Student #" << index + 1 << " Name: ";
        cin >> ptr[studentNum].name;
        cout << "ID Number: ";
        cin >> ptr[studentNum].idNum;

        for(int testNum = 0; testNum < NUM_TESTS; testNum++)
        {
            cout << "student " << testNum << " test score #" << NUM_TESTS << '\\
n';
            cout << "      Test #" << index2 + 1 << ": ";
            cin >> ptr[testNum].testScores[NUM_TESTS];

            index2++;
        }

        index++;
    }

}

Now look again at line 19. Ptr is the student array. Is ptr[testNum] the right student? Is testScores[NUM_TESTS] the right test number?
I've updated the code like this:
It looks like it is outputting the correct student number and test number but something is not letting me output the total correctly and the average, what I have been noticing with the previous code before is that when I try to find the average it would take the first number from the IdNum and use it to divide 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
void getInfo(Student students[], int size)
{

    double index = 0;
    double index2 = 0;
    double total = 0;
    double divide = 4;

    for(int studentNum = 0; studentNum < size; studentNum++)
    {
        cout << "Student #" << index + 1 << " Name: ";
        cin >> students[studentNum].name;
        cout << "ID Number: ";
        cin >> students[studentNum].idNum;

        for(int testNum = 0; testNum < NUM_TESTS; testNum++)
        {
            cout << "      Test #" << index2 + 1 << ": ";
            cin >> students[testNum].testScores[NUM_TESTS];

            total += students[testNum].testScores[NUM_TESTS];


            index2++;
        }

        //students[studentNum].average = total / divide;

        index2 = 0;

        index++;

        cout << endl;
    }

}

Last edited on
I have the output of the student number and test number to output successfully my main problem now is just getting the test scores to add up correctly for each student and then find the average for each individual student.
Pay attention.
dhayden wrote:
Is students[testNum] the right student?
Is testScores[NUM_TESTS] the right test number?

The answer to both is NO.

We know that
1
2
3
4
5
6
const int NUM_TESTS = 4;
struct Student
{
    int testScores[NUM_TESTS];
    // ...
};

Therefore,
testScores[0] is a place for score
testScores[1] is a place for score
testScores[2] is a place for score
testScores[3] is a place for score
testScores[4] is NOT valid. It is an error.
How can I go about fixing this error?
The first time through the loop, you should store it in testScores[0].
The second time, store it in testScores[1].
The third time in testScores[2].

See the pattern? Is there a variable that follows that pattern?

Please understand that we're trying to get you to think your own way through this. It's the only way that you'll learn.
Lets test with simpler case. Can you complete this program to print the values that are in samples?
1
2
3
4
5
6
7
8
#include <iostream>

int main() {
  constexpr int N {4};
  int samples[N] {7, 42, 3};

  // print elements of samples  
}
Yessir! Like this,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include<iostream>

using namespace std;

int main()
{
  constexpr int N {4};
  int samples[N] {7, 42, 3};

    for(int i = 0; i < N; i++)
    {
        cout << samples[i] << endl;
    }


    return 0;
}
@Dhayden

Are you talking about something like this?

1
2
3
4
5
6
7
8
9
10
        for(int studentNum = 0; studentNum < numTests; studentNum++)
        {
            cout << "      Test #" << index2 + 1 << ": ";
            cin >> students[studentNum].testScores[NUM_TESTS];

            total += students[studentNum].testScores[NUM_TESTS];


            index2++;
        }


and then having lets say studentNum be where NUM_TESTS is so it can keep incrementing from 0 to 3?

I'm Just following how my instructor said to do it with a global const int called NUM_TESTS in the student struc as testScores[NUM_TESTS]

like so


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include<iostream>
#include<iomanip>
#include<cmath>
#include<cstring>

using namespace std;

const int NUM_TESTS = 4;

struct Student
{
    string name;
    int idNum;
    int testScores[NUM_TESTS];
    double average;
    char grade;
};
Last edited on
I also tried doing:



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
void getInfo(Student students[], int size)
{

    double index = 0;
    double index2 = 0;
    double total = 0;
    double numTests = 4;

    for(int studentNum = 0; studentNum < size; studentNum++)
    {
        cout << "Student #" << index + 1 << " Name: ";
        cin >> students[studentNum].name;
        cout << "ID Number: ";
        cin >> students[studentNum].idNum;

        for(int i = 0; studentNum < NUM_TESTS; studentNum++)
        {
            cout << "      Test #" << index2 + 1 << ": ";
            cin >> students[i].testScores[NUM_TESTS];

            total += students[i].testScores[NUM_TESTS];

            students[i].average = total / numTests;

            index2++;
        }

        index2 = 0;

        index++;

        cout << endl;
    }

}


it gives me the right average for the first user but entirely skips the second user
and then having lets say studentNum be where NUM_TESTS is so it can keep incrementing from 0 to 3?
Yes, exactly!

I'm Just following how my instructor said to do it with a global const int called NUM_TESTS in the student struc as testScores[NUM_TESTS]
I think you're getting confused between declaring an array, and actually using it.
1
2
3
4
5
6
7
8
9
10
const int NUM_TESTS = 4;

struct Student
{
    string name;
    int idNum;
    int testScores[NUM_TESTS];
    double average;
    char grade;
};
This says that, among other things, a Student contains an array of integers called testScores. The array has room for NUM_TESTS elements (4).

So there is space to store4 elements in testScores. But to access any specific element in your code, you need to use the appropriate index. In C++, the indexes start at zero, not at 1. So you access the first element with testScores[0], and the second with testScores[1] etc.

The value inside "[" and "]" can be anything that evaluates to an integer type, so you can put a variable in there. In fact, most of the time, you will put a variable there.

Does this make sense?
Yessir! Like this,

Good. I'll take your code and rename some variables:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include<iostream>

using namespace std;

int main()
{
  constexpr int NUM_TESTS {4};
  int testScores[NUM_TESTS] {7, 42, 3};

    for ( int testNum = 0; testNum < NUM_TESTS; testNum++ )
    {
        cout << testScores[testNum] << endl;
    }

    return 0;
}

Do you agree that the program did not change?

If yes, then why in your real homework you write:
1
2
3
4
    for ( int testNum = 0; testNum < NUM_TESTS; testNum++ )
    {
        cout << testScores[NUM_TEST] << endl;
    }

I just got so confused with naming the struc and then the array inside the struc
Last edited on
I modified the code a bit and it gives me the correct average for the first user but not for the second here is the output along with my code:

OUTPUT:
Course Grade Program
========================================

How many students: 2

Student #1 Name: Joe
ID Number: 1337
Test #1: 4
Test #2: 4
Test #3: 4
Test #4: 4

Student #2 Name: Mama
ID Number: 1338
Test #1: 5
Test #2: 5
Test #3: 5
Test #4: 5

------ Course Grade Report: --------------
Student Name: Joe
ID Number: 1337
Average Test Score: 4
Grade:
-------------------------------------------------
Student Name: Mama
ID Number: 1338
Average Test Score: 9
Grade:
-------------------------------------------------

Process returned 0 (0x0) execution time : 11.408 s
Press any key to continue.


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
void getInfo(Student students[], int size)
{

    double index = 0;
    double index2 = 0;
    double total = 0;
    double numTests = 4;

    for(int studentNum = 0; studentNum < size; studentNum++)
    {
        cout << "Student #" << index + 1 << " Name: ";
        cin >> students[studentNum].name;
        cout << "ID Number: ";
        cin >> students[studentNum].idNum;

        for(int i = 0; i < NUM_TESTS; i++)
        {
            cout << "      Test #" << index2 + 1 << ": ";
            cin >> students[studentNum].testScores[i];

           total += students[studentNum].testScores[i];

            students[studentNum].average = total / numTests;

            index2++;
        }

        index2 = 0;

        index++;

        cout << endl;
    }

}


am i doing the calculation wrong?
Last edited on
Insert to line 15:
cout << "Total of scores of student " << studentNum+1 << " before reading scores is " << total << '\n';

Insert to line 27:
cout << "Total of scores of student " << studentNum+1 << " after reading scores is " << total << '\n';

What does the resulting output tell you?
Last edited on
Pages: 123