Dynamic Arrays of Students

Mar 26, 2017 at 12:11am
Hi! I'm a little stuck in this project I am trying to program that acts as a class roster. My plan was to create a class with the variables name, numClasses, and classList. Basically I want each student variable to have a dynamic array attached to it. Then I want to be able to create another dynamic array of those student variables to create a class roster that can show every student's classes. I am having trouble with the operators >> and <<. Here is what I have so far, I am omitting my constructors:

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
#include <iostream>
#include <cstdlib>
#include <string>
using namespace std;

typedef string* StrPtr;
class student
{
private:
	string name;
	int numClasses;
	StrPtr classList = new string[numClasses];
public:
	student(string studentName);
	student(string studentName, int number);
	student();
	string getName()const { return name; }
	int getNumClasses()const { return numClasses; }
	friend istream& operator >> (istream& inputStream, student& student);
	//friend ostream& operator << (ostream& outputStream, student& student);

};
istream& operator >> (istream& inputStream, student& student)
{
	cout << "Please enter a student's first name: " << endl;
	inputStream >> student.name;
	cout << "Please enter the number of classes " << student.getName() << " is taking: " << endl;
	inputStream >> student.numClasses;
	StrPtr a;
	a = new string[student.numClasses];
	for (int i = 0; i <= student.numClasses; i++)
	{
		cout << "Please enter " << i+1 << " class: " << endl;
		inputStream >> student.classList[i];
	}
	return inputStream;
}

int main()
{
	student student1;
	cin >> student1;
	system("pause");
	return 0;
}
Last edited on Mar 26, 2017 at 12:12am
Mar 26, 2017 at 1:16pm
the following program uses std::unique_ptr instead of raw C-style pointers which can be unsuitable for your program because the object is acquiring resources but not through the ctor - so even if you provided a dtor with delete[] etc (and also provided the rule of 3/5) there is no guarantee that another object would not be initialized entirely on the stack but it's dtor would then try to call delete[] on a stack allocated variable which is not safe:
http://stackoverflow.com/questions/441831/calling-delete-on-variable-allocated-on-the-stack

for (int i = 0; i <= student.numClasses; i++) c-style arrays are null terminated and the last element of the array is reserved for the '\0', so you need to stop the loop at least 1 less than i. so the correct loop would be:
 
for (int i = 0; i < student.numClasses; i++)

full program:
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
#include <iostream>
#include <memory>//for std::unique_ptr
#include <string>
using namespace std;

typedef string* StrPtr;
class student
{
private:
	string name;
	size_t numClasses;
	//StrPtr classList = nullptr;
	std::unique_ptr<std::string []> classList = nullptr;
public:
	student(string studentName);
	student(string studentName, int number);
	student(){}
	~student(){std::cout << "Goodbye: " << name << "\n"; /*delete student.classList;//not safe for stack allocated variable//*/}
	string getName()const { return name; }
	int getNumClasses()const { return numClasses; }
	friend istream& operator >> (istream& inputStream, student& student);
	friend ostream& operator << (ostream& outputStream, const student& student);

};
istream& operator >> (istream& inputStream, student& student)
{
	cout << "Please enter a student's name: " << endl;
	getline(inputStream, student.name);//use getline() for strings
	cout << "Please enter the number of classes " << student.name << " is taking: " << endl;
	inputStream >> student.numClasses;
	//student.classList = new string[student.numClasses];
	student.classList = std::move(std::make_unique<std::string []>(student.numClasses));
	for (size_t i = 0; i < student.numClasses; ++i)
	{
		cout << "Please enter " << i+1 << " class: " << endl;
		inputStream >> student.classList[i];
	}
	return inputStream;
}
ostream& operator << (ostream& outputStream, const student& student)
{
    outputStream << "Student " << student.name << " takes " << student.numClasses << " classes which are: \n";
    for (size_t i = 0; i < student.numClasses; ++i)
    {
        outputStream << student.classList[i] << "\n";
    }
    return outputStream;
}

int main()
{
	student student1;
	cin >> student1;
	std::cout << student1;

	return 0;
}


Mar 26, 2017 at 4:15pm
Oh my gosh thank you! You are a gift! So now that I have the basic input and output capabilities, I can create another dynamic array of those student variables, correct? In order to have a fully functioning class roster? Or would I be taking too much away from the freestore with all the dynamic arrays I am creating?
Mar 26, 2017 at 6:23pm
Why use a dynamic array instead of a vector? Vector resizes itself dynamically.
Mar 26, 2017 at 6:45pm
So now that I have the basic input and output capabilities, I can create another dynamic array of those student variables, correct?

one possible dynamic allocation on top of another! in my opinion that'd be too unsafe as far as memory managment is concerned unless you really know what you're doing. instead, i'd strongly suggest using std::vector<student> as the container of choice if your program design is evolving in these directions, something on the lines of:
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
#include <iostream>
#include <utility>//for std::move
#include <string>
#include <vector>
using namespace std;

class student
{
private:
	string m_name;
	size_t m_numClasses;
	std::vector<std::string> m_classList;
public:
	student(){}
	student(const string name, const int numClasses, const std::vector<std::string>& classList) :
	    m_name(name), m_numClasses(numClasses), m_classList(classList){}

	//string getName()const { return name; }
	//int getNumClasses()const { return numClasses; }
	friend istream& operator >> (istream& inputStream, student& student);
	friend ostream& operator << (ostream& outputStream, const student& student);

};
istream& operator >> (istream& inputStream, student& student)
{
	cout << "Please enter a student's name: " << endl;
	getline(inputStream, student.m_name);//use getline() for strings
	cout << "Please enter the number of classes " << student.m_name << " is taking: " << endl;
	inputStream >> student.m_numClasses;
	inputStream.ignore();

	for (size_t i = 0; i < student.m_numClasses; ++i)
	{
		cout << "Please enter " << i+1 << " class: " << endl;
		std::string course{};
		getline(std::cin, course);
		student.m_classList.push_back(std::move(course));
	}
	return inputStream;
}
ostream& operator << (ostream& outputStream, const student& student)
{
    outputStream << "Student " << student.m_name << " takes " << student.m_numClasses << " classes which are: \n";
    for (size_t i = 0; i < student.m_numClasses; ++i)
    {
        outputStream << student.m_classList[i] << "\n";
    }
    return outputStream;
}

int main()
{
	student student1, student2;
	std::cin >> student1;
	std::vector<student> allStudents{};
	allStudents.push_back(std::move(student1));
	std::cin >> student2;
	allStudents.push_back(std::move(student2));

	for (const auto& elem : allStudents)std::cout << elem << "\n";

	return 0;
}

Last edited on Mar 26, 2017 at 6:51pm
Mar 26, 2017 at 7:01pm
Unfortunately it's for an assignment that means we can only use dynamic arrays. I would use a vector if I could.
Mar 27, 2017 at 12:09am
closed account (E0p9LyTq)
A vector IS a dynamic array, a fixed-sized array and a vector both order their elements in a contiguous manner.

http://en.cppreference.com/w/cpp/container
Topic archived. No new replies allowed.