Domanda

I'm student working on a problem involving arrays, pointers, structs and de/referencing. I understand about what each means on its own and general initializing of each, but I'm feeling like I'm still not using them properly in my program. What I have runs/works just fine but I'd like to know if there are better ways to be using these??

The general program requirements are as follows: (I've included lines that I think cover each in question. I want to be sure I'm using and incorporating each line properly into the program. Mainly where I am using StudentData[i].testArray)

1 - Use a struct to store following data: name, id#, test (pointer to array of test scores), average, letter grade.

struct StudentData {...};

2 - Ask for number of students and number of tests (same for each student)

3 - Dynamically allocate an array of structures

StudentData *allStudents;
allStudents = new StudentData[numStudents];

4 - Each structure's Tests member should point to a dynamically allocated array of test scores.

double *testsArray;
for (int i=0; i < numStudents; i++)
{
    allStudents[i].testsArray = new double[numTests];
}
//does this need to be deleted with a for loop as well??

5 - Compute test average and letter grade

6 - Display Information

Full code:

// Course Grade
// A program to gather and display a collection of student information. 
// Programmer Name : Chuck
// C++ II

#include <iostream>
#include <string>
#include <iomanip>
using namespace std;

//structure to hold data for each student
struct StudentData
{
    string studentName;
    int studentID;
    double *testsArray;     //pointer to an array of test scores
    double testAverage;     //calculated average test score
    char courseGrade;       //calculated course letter grade (A-F)
};


//function prototypes
string getName();
int getID();
double getScore(int count);
char calcGradeLetter(double *testAverage);
void displayData (StudentData allStudents[], int sCount);



int main()
{   cout << "   Welcome to the Test Score Storer. This program will gather test\n";
    cout << "scores for a given student name/id#. We'll start with some questions.\n\n";

    int numTests;
    cout << "How many test scores per student? : ";
    cin  >> numTests;

    int numStudents;
    cout << "How many students?                : ";
    cin  >> numStudents;

    cout << "Creating Database...";
    //create array to hold all studentData structs
    StudentData *allStudents;
    allStudents = new StudentData[numStudents];
    cout << "...";
    //create a tests member array for each student struct
    double *testsArray;
    for (int i=0; i < numStudents; i++)
    {
        allStudents[i].testsArray = new double[numTests];
    }
    cout <<"...Done!\n";
    system ("pause");
    system ("CLS");


    //TRYING
    for (int i=0; i < numStudents; i++)
    {
        cout << "Student " << i+1 << " of " << numStudents << endl;
        cout << "=================================\n";
        allStudents[i].studentName = getName();
        allStudents[i].studentID = getID();
        double testTotal = 0.0;
        for (int j=0; j < numTests; j++)
        {
            allStudents[i].testsArray[j] = getScore(j);
            testTotal += allStudents[i].testsArray[j];
            allStudents[i].testAverage = testTotal/numTests;
        }
        //calculate letter grade
        allStudents[i].courseGrade = calcGradeLetter(&allStudents[i].testAverage);
        cout << "Student,  " << allStudents[i].studentName << ", completed.\n";
        system ("pause");
        system ("CLS");
    }

    //Display all collected student data in chart form
    displayData(allStudents, numStudents);


    delete [] allStudents;
    system ("pause");
    return (0);
}


//===========FUNCTIONS===========FUNCTIONS===========FUNCTIONS
string getName()
{
    string name;
    cout << "Student Name  : ";
    cin  >> name;
    return name;
}

int getID()
{
    int IDnum;
    cout << "Student ID    : ";
    cin  >> IDnum;
    return IDnum;
}

double getScore(int count)
{
    double score;
    score = -500;
    while (score <0)
    {   cout << "Test Score #" << count+1 <<" : ";
        cin  >> score;
        if (score < 0)
        {
            cout << "Scores cannot be less than 0, try again.\n";
        }
    }   
    return score;
}


char calcGradeLetter(double *testAverage)
{
    if (*testAverage >= 90) return 'A';
    else if (*testAverage >= 80) return 'B';
    else if (*testAverage >= 70) return 'C';
    else if (*testAverage <  70) return 'F';
    else return ('X');
}

void displayData(StudentData allStudents[], int sCount)
{
    cout << "Student Data Chart:\n";
    cout << "=================================================\n";
    cout << "NAME               ID#          TEST AVE.   GRADE\n";
    for (int i = 0; i < sCount; i++)
    {
        cout << left << setw(18) << allStudents[i].studentName << " "
             << left << setw(12) << allStudents[i].studentID << " "
             << left << setw(11) << setprecision(4) << allStudents[i].testAverage << " "
             << allStudents[i].courseGrade << endl;
    }
    cout << "\nTable complete. ";
    }

This is my first post on Stack, sorry if this lands in the wrong place or comes across as homework needy, I'm not just looking for an easy answer. I am a new developer, eager to learn. This topic is just something I'm having a lot of trouble working with.

È stato utile?

Soluzione

The short answer to your question is yes, there are better ways to accomplish the result.

The longer answer is that due to the nature of your assignment and the requirements that you have to deal specifically with memory allocation and deallocation (which, by the way, I don't see where you are deallocating the testscores for each student. You need to loop through each student before deleting it and delete the test scores array), it limits you from using things like std::vector, which would handle all of the array issues for you.

Just to help with the memory management a bit:

struct StudentData
{
    StudnetData() : studentID(0), testsArray(NULL), testAverage(0.0), courseGrade('N')
    {

    }

    ~StudentData()
    {
        delete [] testsArray;
    }

    string studentName;
    int studentID;
    double *testsArray;     //pointer to an array of test scores
    double testAverage;     //calculated average test score
    char courseGrade;       //calculated course letter grade (A-F)
private:
    StudentData(const StudentData&); // unimplemented intentionally
    StudentData& operator= (const StudentData&); // unimplemented intentionally
};

Then, when you delete the student array:

delete [] allStudents;

Any tests they have will also be deleted.

Altri suggerimenti

Eh, this is largely fine given that you're asked to use new rather than the standard practice of types like std::vector.

C++ does have tools you could use to wrap up this usage of new to make it easier, safer, more automatic, etc., while still complying with the requirements. You'd essentially be implementing a simplified version of vector. However you probably haven't learned all the necessary parts of C++.

structs TestsArray {
  double *scores;
  // constructors, destructors, etc. to make this behave properly
  // ...
};

structs StudentsArray {
  StudentData *students;
  // basically the same as for TestArray; templates avoid this duplication
};

Also for the grade you might define an enum:

enum Grade { A, B, C, D, F};

This way you're less likely to encounter an invalid grade (e.g., 'e') somewhere.

struct StudentData
{
  string studentName;
  int studentID;
  TestsArray testsArray;
  double testAverage;
  Grade courseGrade;
};


cout << "Creating Database...";
//create array to hold all studentData structs
StudentsArray allStudents(numStudents, numTests);
cout <<"...Done!\n";

// allStudents will automatically be cleaned up at the end

//does this need to be deleted with a for loop as well??

Yes, or at least you need to somehow arrange for every Student's testsArray to be deleted.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top