Dynamically Allocating an array of structures

Pages: 123
I am working on a program where I can select how many students I can enter data for, I am not familiar with vectors and am new when it comes to dynamic arrays within structures. Test scores has a fixed array size of 4 and is not changed since every student requires four test scores. I am just looking to dynamically allocate an array successfully and I think i should be able to do the rest.

I am trying to get an input like this:

How many students are you entering data for: 2

Student #1 Name:
ID:
Test Score #1
Test Score #2
Test Score #3
Test Score #4
-----------------------
Student #2 Name:
ID:
Test Score #1
Test Score #2
Test Score #3
Test Score #4

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
#include<iostream>
#include<iomanip>
#include<cmath>
#include <cstring>
#include <cctype>
#include <cstdlib>

using namespace std;

const int NUM_TESTS = 4;

struct Student
{
    string name;
    int idNum;
    int testScores[NUM_TESTS];
    double average;
    char grade;
};

// Function prototypes
Student *initarrays(int);
void getInfo(Student [], int);
void showInfo(Student [], int);

int main()
{
    int numStudents;    //Local integer variable that holds the number of students
    Student *pointer;   //Pointer that points to the student struc array

    cout << "          Course Grade Program" << endl;
    cout << "========================================\n" << endl;
    cout << "How many students: ";
    cin >> numStudents;

    cout << endl;

    pointer = new Student[numStudents];

    return 0;
}

}
Last edited on
At line 38, you are correctly dynamically allocating an array of the correct number of Student objects.

So what's the problem?

EDIT: And please don't create multiple threads for the same question. You've already been getting answers to this issue in one of your other threads.
Last edited on
Hello Depressed,

I do not see any problem with what you have except that "cstring" and "cstdlib" may not be needed or needed yet.

Line 43 is an extra closing brace that is not needed.

You have used "new' to create memory, but you need "delete" before the "return 0" to free the memory. Do not count on the program ending to free the memory.

With what you posted there it is difficult to test if "new" worked. I will have to work on that.

Andy
I have gotten this far, I am currently trying to fix the problem in my function since it crashes after the name input.

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
61
62
#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;
};

// Function prototypes
Student *initarrays(int);
void getInfo(Student [], int);
void showInfo(Student [], int);

int main()
{
    int numStudents;    //Local integer variable that holds the number of students
    Student *pointer;   //Pointer that points to the student struc array

    cout << "          Course Grade Program" << endl;
    cout << "========================================\n" << endl;
    cout << "How many students: ";
    cin >> numStudents;

    cout << endl;

    pointer = new Student[numStudents];

    getInfo(pointer, numStudents);

    delete pointer;

    return 0;
}

void getInfo(Student prGroup[], int size)
{
    Student* ptr;
    int index = 0;
    int testScore = 0;
    int convert;

    for(int numCount  = 0; numCount < size; numCount++)
    {
        cout << "Student name#" << index + 1 << ": ";
        cin >> ptr->name;

        cout << "ID Number: ";
        cin >> ptr->idNum;

        index++;
    }
}
In your getInfo() function, you never set the value of ptr to anything. It's pointing to random memory. So when you try and put data into that random memory, you get undefined behaviour.

You're lucky that, in this case, it causes a crash.
In getInfo, ptr has never been initialized. When you try to dereference it (with the -> operator) your program crashes.

Also, since pointer points to an array, delete pointer should be delete[] pointer.

BTW, "pointer" is a bad name, only slightly better than "bag_o_bits". Yes it's a pointer, but it points to an array of student information. So maybe "students" would be better. And unless "prGroup" means something it could just be "students", too.

Maybe you mean something like this:

1
2
3
4
5
6
7
8
9
10
11
void getInfo(Student students[], int size)
{
    for (int i = 0; i < size; ++i)
    {
        cout << "Student name#" << i + 1 << ": ";
        cin >> students[i].name;

        cout << "ID Number: ";
        cin >> students[i].idNum;
    }
}

Last edited on
I am slowly working my way into making this function work appropriately, I changed up the function to this

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void getInfo(Student prGroup[], int size)
{
    Student *ptr;

    int index = 0;

    for(ptr = prGroup; ptr < &prGroup[size]; ptr++)
    {
        cout << "Student Name: ";
        cin >> ptr->name;
    }

}
Last edited on
Are you deliberately experimenting with pointer arithmetic? Because otherwise, it would be much more intuitive to do:

7
8
9
10
11
    for (int i = 0; i < size; i++)
    {
        cout << "Student Name: ";
        cin >> ptr[i].name;
    }
We are currently learning pointers so I was trying it that way, ill use non pointers and see how it simplifies the process.
Last edited on
Fair enough. There's nothing wrong with doing it that way, if you're doing it as a learning exercise to get familiar with pointers.
Last edited on
how would I go about making the testScores variable work in the forloop? Since it has a fixed array size of four, because I would like it to output four test scores per student.

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
void getInfo(Student *ptr, int size)
{

    int index = 0, 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 << "      Test #" << index2 + 1 << ": ";
            cin >> ptr[i].testScores;

            index2++;
        }

        index++;
    }

}
Last edited on
Hello Depressed,

Once I got into the program I made a few adjustments.

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
61
62
63
64
65
66
67
#include<iostream>
#include<iomanip>
//#include<cmath>   // <--- Not used yet and may not be needed.
#include <string>   // <--- Changed.
//#include <cctype> // <--- Not used right now.
#include <limits>   // <--- Added.

using namespace std;

const int NUM_TESTS = 4;

struct Student
{
	string name;
	int idNum;
	int testScores[NUM_TESTS];
	double average;
	char grade;
};

// Function prototypes
Student *initarrays(int);
void getInfo(Student prGroup[], int size);
void showInfo(Student student[], int size);

int main()
{
	int numStudents;      // Local integer variable that holds the number of students
	Student *studentPtr;  // Pointer that points to the student struc array

	cout << "          Course Grade Program\n";
	cout << "========================================\n" << endl;

	cout << "How many students: ";
	cin >> numStudents;
	std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');  // <--- Requires header file <limits>.

	//cout << endl; // <--- To many blank lines

	studentPtr = new Student[numStudents];

	getInfo(studentPtr, numStudents);

	showInfo(studentPtr, numStudents);

	delete[] studentPtr;

	return 0;
}

void getInfo(Student studentPtr[], int size)
{
	Student* ptr;
	int index = 0; // <--- Do not see the use of this variable?

	for (ptr = studentPtr; ptr < &studentPtr[size]; ptr++)
	{
		cout << "\n Student name for #" << index + 1 << ": ";
		std::getline(std::cin, ptr->name);

		cout << " ID Number: ";
		std::cin >> ptr->idNum;
		std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');  // <--- Requires header file <limits>.
        }

        // Rest of input.
}

In the "getInfo" function I adjusted what you did previous. In the end dutch has a better solution that is much simpler and easier to work with.

With the "getInfo" function I used I got this output:

          Course Grade Program
========================================

How many students: 1

 Student name for #1: Nigel Smithe
 ID Number: 123456

 Enter test score 1: 95

 Enter test score 2: 89

 Enter test score 3: 96

 Enter test score 4: 99


 You entered:

 Name: Nigel Smithe
 ID: 123456
 Test scores: 95, 89, 96, 99


Just an idea for output. It can be changed.

Andy
Thank you for your insight Andy! You are always a great help as well, I will look into modifying and making your perspective fit my formatting style and also see where I can improve on.
I've gotten a bit far, the only problem now is that the # of test does not reset after every iteration of a new user, and also

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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#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;
};

// Function prototypes
void getInfo(Student *, int);
void showInfo(Student *, int);

int main()
{
    int numStudents = 0;    //Local integer variable that holds the number of students
    Student *pointer;   //Pointer that points to the student struc array

    cout << "          Course Grade Program" << endl;
    cout << "========================================\n" << endl;
    cout << "How many students: ";
    cin >> numStudents;

    cout << endl;

    pointer = new Student[numStudents];

    getInfo(pointer, numStudents);
    showInfo(pointer,numStudents);

    delete [] pointer;

    return 0;
}

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 << "      Test #" << index2 + 1 << ": ";
            cin >> ptr[i].testScores[NUM_TESTS];

            index2++;
        }

        index++;
    }

}

void showInfo(Student *ptr, int size)
{

        // Prints ID number, name, and salary for 5 programmers.
        cout << "------ Course Grade Report: --------------\n";
        // for(int index = 0; index < MAX_PROG; index++)
        for(int i = 0; i < size; i++)
        {
        cout << "Student Name: " << ptr[i].name << endl;
        cout << "ID Number: "  << ptr[i].idNum << endl;
        cout << "Average Test Score: " << ptr[i].average <<  endl;
        cout << "Grade: " << ptr[i].grade << endl;
        cout << "-------------------------------------------------\n";
        }
}
# tests print is tied to index2 which is only set to zero outside the loops. if you want it zero for each outer loop go, then put index2=0; in the outer loop.

and also?
I forgot to type out the other part, How would I get the average to work out correclty?
I have something like this:

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

void getInfo(Student students[], int size)
{

    double index = 0;
    double index2 = 0;

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

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

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

            index2++;
        }
        index2 = 0;

        index++;
    }
The average is the sum of scores, divided by the number of scores.

Hint: be careful of integer division.
I implemented it, I got some weird notation as an output...
You do understand that we can't see your monitor, right?

We can't know what your "weird notation" is, without you actually showing it to us.

And we can't see whatever problems might be in your code, without you actually showing it to us.
I implemented it like this:


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

void getInfo(Student students[], int size)
{

    double index = 0;
    double index2 = 0;

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

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

            students[i].average += students[i].testScores[NUM_TESTS] / NUM_TESTS;

            index2++;
        }
        index2 = 0;

        index++;
    }

}



and the output I get is,

Course Grade Program
========================================

How many students: 2

Student #1 Name: Joe
ID Number: 1
Test #1: 1
Test #2: 1
Test #3: 1
Test #4: 1
Student #2 Name: Mama
ID Number: 2
Test #1: 2
Test #2: 2
Test #3: 2
Test #4: 2
------ Course Grade Report: --------------
Student Name: Joe
ID Number: 1
Average Test Score: 0
Grade:
-------------------------------------------------
Student Name: Mama
ID Number: 2
Average Test Score: 9.72658e-315
Grade:
-------------------------------------------------

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

Pages: 123