Advice on Dynamically Allocating data for a structure

Would like advice on dynamically allocating a structures array, so it could be modified with a cin.

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

using namespace std;

const int NUM_TESTS = 4;
const int SIZE = 40;

struct studentInfo
{
    char studentName[SIZE];
    char idNum[SIZE];
    double testScores[NUM_TESTS];
    double average;
    char grade[SIZE];
};

void getInfo(studentInfo [], int);
void showInfo(studentInfo [], int);

int main()
{
    const int MAX_INFO = 4;

    studentInfo student[MAX_INFO];
    cout << "          Course Grade Program" << endl;
    cout << "========================================\n" << endl;

    getInfo(student,MAX_INFO);

    return 0;
}

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

    for(ptr = prGroup; ptr < &prGroup[size]; ptr++)
    {
        cout << "Student name#" << index + 1 << ": ";
        cin.getline(ptr->studentName, SIZE);
        
        cout << "ID Number: ";
        cin.getline(ptr->idNum, SIZE);

        index++;
    }
}

void showInfo(studentInfo array[], int size)
{

}
Last edited on
Line 40: You declare a pointer to a StudentInfo object.
Line 46: You attempt to dereference this pointer.

ptr is just a pointer. It's not pointing to actual data, though.

You already have studentInfo objects -- the array you passed in.
Do cin.getline(prGroup[index].studentName, SIZE);
instead.


Disregard me. See zapshe's post. But one note: It would be better if you declared your StudentInfo* ptr within the for loop.
Last edited on
Your for loop is slightly odd. You've created a pointer, pointed it to the memory address of the first element of prGroup, and then you're checking if that memory address is less than the memory address of prGroup[size]. I assume your professor wrote this loop?


Anyway, you can easily gather the test scores within the getInfo function, the loop is already made for you. You'd just add a few extra lines (this code assumes 4 test score per student):

1
2
3
4
5
for(int i = 0; i < NUM_TESTS; i++)
{
      cout << "Test Score " << i << ": ";
      std::cin >> ptr->testScores[i];
}


This loop would go inside the already existing one.


EDIT

@Ganado On line 43, he sets the pointer to prGroup.
Last edited on
I got it to work, I am just stuck on creating a dynamic array for the structure,

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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#include<iostream>
#include<iomanip>
#include<cmath>
#include <cstring>
#include <cctype>
#include <cstdlib>

using namespace std;

const int NUM_TESTS = 4;
const int SIZE = 40;

struct studentInfo
{
    char studentName[SIZE];
    char idNum[SIZE];
    char testScores[NUM_TESTS];
    double average;
    char grade;
};

void getInfo(studentInfo [], int);
void showInfo(studentInfo [], int);

int main()
{
    const int *ARRAY_SIZE = nullptr;   //Local double pointer to dynamically allocate an array
    int DYNAMIC;

    studentInfo student[ARRAY_SIZE];
    cout << "          Course Grade Program" << endl;
    cout << "========================================\n" << endl;
    cout << "How many students: ";
    cin >> DYNAMIC;

    ARRAY_SIZE = new const int[DYNAMIC];  //Dynamically allocates an array large enough to hold both strings and names

    getInfo(student,ARRAY_SIZE);
    showInfo(student,ARRAY_SIZE);

    return 0;
}

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

    for(ptr = prGroup; ptr < &prGroup[size]; ptr++)
    {
        cout << "Student name#" << index + 1 << ": ";
        cin.getline(ptr->studentName, SIZE);

        cout << "ID Number: ";
        cin.getline(ptr->idNum, SIZE);

        for(int numCount = 0; numCount < NUM_TESTS; numCount++)
        {
            cout << "      Test #" << numCount + 1 << ": ";
            cin.getline (ptr->testScores, NUM_TESTS);

            int e = atoi(ptr->testScores);
            ptr->average += e/2;

            /*if(ptr->grade >= 91 || ptr->grade <= 100)
            {
                ptr->grade = 'A';
            }
            if(ptr->grade >= 91 || ptr->grade <= 90)
            {
                ptr->grade = 'B';
            }
            if(ptr->grade >= 71 || ptr->grade <= 80)
            {
                ptr->grade = 'C';
            }
            if(ptr->grade >= 61 || ptr->grade <= 70)
            {
                ptr->grade = 'D';
            } */
        }
        cout << endl;

        index++;
    }
}

void showInfo(studentInfo prGroup[], int size)
{
        studentInfo* ptr;

        // Prints ID number, name, and salary for 5 programmers.
        cout << "------ Course Grade Report: --------------\n";
        // for(int index = 0; index < MAX_PROG; index++)
        for(ptr = prGroup; ptr < &prGroup[size]; ptr++)
        {
        cout << "Student Name: " << ptr->studentName << endl;
        cout << "ID Number: "  << ptr->idNum << endl;
        cout << "Average Test Score: " << ptr->average <<  endl;
        cout << "Grade: " << ptr->grade << endl;
        cout << "-------------------------------------------------\n";
        }
}
Last edited on
I am just stuck on creating a dynamic array for the structure

This is too out of context to know what you mean :( Glad you go it going.

Btw, some of your code is very reminiscent of C, C++ has plenty of features that would make what you're doing much easier and simpler. If this is for your own practice, you should try to get some experience with making this program using more updated methods.
That is true, for this program i just need to get dynamic arrays working so I can modify the array size whenever I enter an input and it can show the right amount of users to enter the data for.
There are more than one way.

You had static array and you did use all of it:
1
2
3
    const int MAX_INFO = 4;
    studentInfo student[MAX_INFO];
    getInfo( student, MAX_INFO );

You could have static array, but use only part of it:
1
2
3
4
5
6
    const int MAX_INFO = 42;
    studentInfo student[MAX_INFO];
    int info = 0;
    std::cin >> info;
    if ( MAX_INFO < info ) info = MAX_INFO;
    getInfo( student, info );

For dynamic array, default to vector:
std::vector<studentInfo> student = getInfo();

If you really have to do it manually, then you should manage the deallocation too:
1
2
3
4
5
    int info = 0;
    std::cin >> info;
    studentInfo* student = new studentInfo[ info ];
    getInfo( student, info );
    delete [] student;

Last edited on
I tried it your way, only thing is, it messes up my for loop and skips the student name entry.
Another example:
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 <iomanip>
#include <iostream>


struct StudentInfo {
    static constexpr int Num_Tests { 4 };
    static constexpr int Size { 40 };

    char student_name[Size] {};
    char id_num[Size] {};
    double test_scores[Num_Tests] {};
    double average {};
    char grade[Size] {};
};


void getInfo( StudentInfo* const, int );
void showInfo( StudentInfo* const, int );


int main()
{
    constexpr int Max_Info { 4 };

    StudentInfo students[Max_Info];
    std::cout << "          Course Grade Program\n"
                 "========================================\n";

    getInfo( students, Max_Info );

    return 0;
}


void getInfo( StudentInfo* const pr_group, int size )
{
    for (int i {}; i < size; ++i) {
        std::cout << "\nStudent #" << i + 1 << "\nname? ";
        std::cin.getline( pr_group[i].student_name, StudentInfo::Size );

        std::cout << "ID Number: ";
        std::cin.getline( pr_group[i].id_num, StudentInfo::Size );
    }
}


//void showInfo(StudentInfo* const myarray[], int size)
//{
//} 

I tried it your way, only thing is, it messes up my for loop and skips the student name entry.

I did list four different approaches. Hard to say what you did (wrong).

My changes were in main(). Only the vector-based version requires changes into functions. In other words, my solutions (if correctly implemented) cannot possibly mess up your loops. Either your loops were messed up to begin with, or you failed to apply the idea to your code.


Lets look at your code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
void getInfo(studentInfo [], int);

int main()
{
    double *ARRAY_SIZE = nullptr; // ARRAY_SIZE is a pointer
    int dynamic = 0;
    cin >> dynamic;
    ARRAY_SIZE = new double[dynamic];  // ARRAY_SIZE points to dynamic array of double values

    studentInfo student[ARRAY_SIZE]; // static array of studentInfo values
    // error: pointer is not integer
    // error: size of static array must be constant integer

    getInfo(student,ARRAY_SIZE); // error: function expects int, ARRAY_SIZE is pointer 

What were you thinking?
Last edited on
I was trying to point the dynamic array of double values to the structure so I could create a dynamic structure that can be modified like a regular dynamic array and I can either choose to input data for one student only or four.
"a regular dynamic array"?
All dynamic arrays are "regular". There are no "irregular arrays".

"dynamic structure"?
You are not supposed to change studentInfo, just where you keep them.

How would {3.14, 2.7, 6.9} make anything "dynamic"?
How would I go about altering the amount of students I would like to enter data for. For example: I enter "1" because I only want to enter data for one student or "3" for three separate students and not rely on a fixed number for an array size?
for a vector:

cin >> size;
vector<type> name(size); //pretty much like type name[size].
name[0] = first...
name[1] = second... just like an array.

for pointers.
cin >> size;
type *name = new type[size];
name[0] = first;... etc

if you need to change the sizes later, the pointer needs a do-over, you make a new bigger one and copy everything into it, or use C's realloc. Vectors can simply be extended using push_back(oops_needed_one_more_nth_input) or other ways easily.


Remember the static array:
1
2
const int MAX_INFO = 4; // this is decided before you compile the program
studentInfo student[MAX_INFO]; // array of MAX_INFO students 

vs dynamic array:
1
2
3
int MAX_INFO = 0;
std::cin >> MAX_INFO; // user decides number of students when the program runs
studentInfo* student = new studentInfo[MAX_INFO]; // array of MAX_INFO students 


And the "we have room for MAX_INFO students, but only N did show up":
1
2
3
int N = 0;
std::cin >> N; // actual students
if ( MAX_INFO < N ) // more than expected, what to do? 

A difference between static and dynamic array is that the size of static is set in stone, but you can replace a dynamic array while the program runs.

This latter point is not important for you, because you receive the count of students before the students arrive. You need to create array only once and it will be of "right size" (unless the user lies*).


*Dr. House: "Everybody lies."
Topic archived. No new replies allowed.