0

This if for my homework.

I have a class called Student that takes 3 parameters (id, name, class) and I want to store each student in an array called Roster (which can only have 7 students).

The user will provides input to add or remove students. Thus, I have to manage the array by creating or deleting students. So if the user specify the student ID, I have to remove him for the array.

I tried to use a fixed array, but I'm struggling to make it works. Is there a better way to implement this?

I must not use a vector or any STL container.

student.h

#ifndef STUDENT_H
#define STUDENT_H
#include <iostream>
#include <string>

static const int SIZE = 7;

class Student {  
        private:
        int student_id;
        std::string name;
        std::string classification;

        public:
        Student(int, std::string, std::string);     // constructor; initialize the list to be empty
        ~Student();
        void print();

    };

#endif

student.cpp

#include <iostream>
#include <string>

#include "student.h"

#define PROMPT "class> "
using namespace std;

Student::Student(int a, string b, string c){
    student_id = a;
    name = b;
    classification = c;
}

Student::~Student(){
    //delete Student
}

void Student::print(){
    cout<<"Enrolled:"<<endl;
    cout<<student_id<<"-"<<name<<"-"<<classification<<endl;
}

main.cpp

#include <iostream>
#include <string>
//#include <sstream>
#include "student.h"

#define PROMPT "class> "
using namespace std;


//**** Implement Error Handling ****\\

enum errorType {
    UNKNOWN_ERROR,
    INPUT_ERROR,
    HANDLER,
    NUM_ERRORS
};

// error messages

string errorMessage[NUM_ERRORS] = {
    "Unknown Error\n",
    "Input Error\n",
};

// error handler

void handleError(errorType err) {
    if(err > 0 && err < NUM_ERRORS)
        cout<< "Error: "<< errorMessage[err];
    else cout<< "Error: "<< errorMessage[UNKNOWN_ERROR];
}

//**** END Error Handling ****\\



void enroll(Student newStudent){
        cout<<"test";
        Student roster[SIZE];
     for(int i=0;i<SIZE;i++){
        newStudent->roster[i];
     }
}

void handleInput() {
    int id; string n, c;

    cin>>id>>n>>c; 
    Student newStudent(id,n,c);
    newStudent.print(); 
    enroll(newStudent);
    //cout<<"hello3"<<endl;
    return;
}


int main() {
    //Student newStudent;   /* <-- why doesn't this work?!*/
    string input = "";
    bool finished = false;

    cout<<PROMPT; // prompt the user
    while(!finished) {
        if(input!="") cout<<PROMPT;
        cin>>input;
        if(input=="enroll") {
            cout<<PROMPT<<"Enroll student:"<<endl;
            handleInput();
        }
        else if(input=="drop") {
            cout<<PROMPT<<"Enter ID:"<<endl;
        }
        else if(input=="roster") {
            cout<<"This will print formatted list of students"<<endl;
        }
        else if(input=="quit") {
            finished=true;
        }
        else handleError(errorType(1));
    }
}
7
  • Why can't you use std::vector? Is this homework? Commented Jun 23, 2012 at 1:57
  • 3
    This includes a Student class, this must be homework! :) Commented Jun 23, 2012 at 1:58
  • 1) don't "write this on the fly"-- the compiler is your friend and will warn you of errors large and small, 2) is there some reason you want an array, and not, say a vector<Student>? Commented Jun 23, 2012 at 2:00
  • yup, it's homework for sure. i'm going to upload the whole thing so it's less confusing Commented Jun 23, 2012 at 2:04
  • I added a reply to explain you some of your mistakes. I was wondering if you are allowed to use your own container? If you can't use a std::vector and the whole STL is not allowed maybe it is because they want you to wrote your own vector/list? In the case your describing, a LinkedLink would do a good job too. Commented Jun 23, 2012 at 2:54

4 Answers 4

2

Since it is a homework, I'd like to point out some mistakes you did because it is important to understand what you are doing in the first place.

You must not program by coincidence, but by trying to understand exactly what's going on. By doing that you will become better and better and the answers should fall in place.

What you've done

So, from what you are describing, the array is fixed. Thus it is a good idea to use a constant as you did (SIZE).

However, as we can see below you a declaring an array of size SIZE in the function. By doing that, your array is like a temporary variable, because its scope is inside the function. Each time you call this function, the array will be declared again and then deleted at the exit. So it should be declared outside.

void enroll(Student newStudent)
{
     cout<<"test";
     Student roster[SIZE]; // Here 'roster' will be available only inside the function.
     
     for(int i=0;i<SIZE;i++)
     {
        newStudent->roster[i]; // Here there is few mistakes see my explanation below*
     }
}

If we look at this part:

newStudent->roster[i];

First of all, the arrow '->' is used with pointers. The dot '.' is used with objects. In both case, it does the same thing, access to public members of Student.

Since you passed

void enroll(Student newStudent)

you should use '.' instead.

newStudent.SomeOfYourMembers;

If the parameter was a pointer to a Student

void enroll(Student *newStudent)

Then, you'd have to use the arrow '->' like you did.

Back to the original statement:

newStudent->roster[i];

This means, you want to access to 'roster' array at position 'i' inside your Student object (newStudent). As you can see in your code, roster is not declared inside Student (and should not be since you want an array of Students), so that won't work.

Guidelines

As I mentionned, your array should be outside the function, so at a higher scope.

Then, if you need an array of student, basically, 'roster[i]' will give you access to the student 'i'. Thus, if you want to print the student, you would do something like that:

roster[i].print();

This would be valid because 'print()' is defined as public.

In order to store a student inside the array, you can do something like:

roster[i] = new Student(0 /* id*/, "name", "classification");

But don't forget, each time you use new, you have to balance it with a delete. And if you are creating the student like this in a loop, you will have to clean them the same way:

for(int i = 0; i < SIZE; ++i)
{
    delete roster[i];
}

Good luck!

Don't hesitate if there is there anything that I could clarify. I hope this helps!

Edit: In reply to your first comment.

Concerning the roster array

No, it is not mandatory to create a class roster you could declare roster in the main.cpp.

The key concept is that by defining

Student roster[SIZE]; 

the array will contains objects of type Student.

What roster[i].print() means is that you are printing one of the Student of that array, in fact the one at position 'i'.

Concerning the print() function

What is powerfull with Object Oriented language, each object will have the same print() function. So, you do not need to convert the array to string.

However, if you want a string to be printed out (or returned) you can write the code inside the print() function that will do this job.

The advantage of this, is that if further on you need to change your array in some ways, your print() function will always work.

Concerning the Delete

When you are doing something like this on an array that contains objects:

delete roster[i];

It will delete the object at the position 'i'. Thus, the destructor of that Student 'i' will be called. If your object Student would contains other object, you would have to delete them in the destructor.

Further notices

Since ID is an input that you are storing into a string, you will have to convert the ID to the same type of the student_id, which is a int. Then you can always write a loop for each student and check their ID to delete the proper one.

Concerning the container, a fixed array might not be the best to achieve this job. You might want to look the LinkedList concept.

Sign up to request clarification or add additional context in comments.

2 Comments

thank you! this is very helpful, my prof is unresponsive "roster[i].print();" does this mean I have to create a class called roster? or would I declare it in main.cpp? unfortunately the delete method has to be user specific, based on the ID they enter and want deleted. (so if student 2 gets removed student 3 must slide in to take it's place) in my print function, I have to convert the array to a string correct? would that be like this: void Student::print() { for(int i=0;i<SIZE;i++){ sstream ss; ss<<Student; string result = ss.str(roster[i]); } }
@conman I will answer your comment question in my answer it will be easier like that.
1

It doesn't make much sense for enroll to be a member function, so I'd wrap the roster into a class to get automatic clean up of my pointers.

#include <cstddef>

struct Student {};

class Roster
{
private:
  static const size_t size = 7; 
  // non-copyable
  Roster(const Roster&);
  Roster& operator=(const Roster&);
public:
  Roster() {
    for(unsigned i = 0; i < size; ++i) {
      roster_[i] = NULL;
    }
  }

  ~Roster() {
    for(unsigned i = 0; i < size; ++i) {
      delete roster_[i];
    }
  }

  // enroll by copy
  bool enroll(const Student& s) {
    for(unsigned i = 0; i < size; ++i) {
      if(roster_[i] == NULL) {
        roster_[i] = new Student(s);
        return true;
      }
    }
    // out of space
    return false;
  }

  // enroll by taking ownership
  bool enroll(Student* s) {
    for(unsigned i = 0; i < size; ++i) {
      if(roster_[i] == NULL) {
        roster_[i] = s;
        return true;
      }
    }
    // out of space
    return false;
  }

private:
  // data
  Student* roster_[size];
};


int main()
{
  Roster r;
  Student s;
  r.enroll(s);
  Student* sp = new Student();
  r.enroll(sp);
  return 0;
}

5 Comments

What about the fact that the question states cannot use vector?
it's an assignment for class, we can't use the STL. otherwise I wouldn't be struggling with this so much.
As he said, he cannot use STL, I don't see how your std::unique_ptr solution would help him in that way.
this is pretty helpful, so I should use another class as a container basically?
@K-ballo Sorry, saw that too late. Should be fixed now.
0

What about this?

Student * roster[2];
roster[0] = new Student(5,"first","2A");
roster[1] = new Student(2,"Second","5B");

Ps:

Enrol and Size shouldn't be members of the student class. Print should ideally be externalized and a ToString function should be added instead.

You should use the inline constructor initialization instead:

Student(int a,string b,string c):id(a),name(b),class(c){}

1 Comment

would it be easier to just have a default constructor and a constructor that takes parameters? --i've never used inline constructor
0

You've used the keyword class as a variable name of type string. You shouldn't do that. Does it even compile like that?

enroll should have two arguments: void enroll( Student enrollee, Student Roster[]). You should probably change the name of Roster to roster because it's not a class and typically class names are capitalized.

If your array will only ever have 7 students then you could use some sentinel value to mark that the current student as an invalid student. Perhaps the id will be -1 to mark this. It means basically that you need some way to keep track of which spots in the array you can still use. If you don't do this then declaring an array of Students will get you an array of students with garbage member variables. You wouldn't be able to tell which students are real ones and which are just place holders for when someone new enrolls in the class. I would create a default constructor of Student and initialize its member variables like this:

id=-1;
name="";
name_of_class="";

I changed the name of your string class to avoid confusion.

After all that, enroll would look something like this:

void Student::enroll( Student enrolee, Student roster[]){

    //search through roster to check for the first student with an
    //id of -1
    //if there are no students with id of -1, produce an error message
    //that the class is full

    //overwrite the student with id of -1  with the id, name, and
    //name_of_class of enrollee


}

Although I'm not sure what exactly string class is there for. Does it store what class the Student is in? Is it their year in school like Freshman, Sophomore?

If you're suppose to use dynamic allocation of roster, though, it's a different story, but you said it will only ever have seven students.

1 Comment

thank you! and yes the 'string class' got changed to 'string classification' i.e. Freshman, Sophomore, etc...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.