0

How would i go about converting this from dynamic to static, all me attempts so far have failed.

#include <iostream>
#include <fstream>
#include <string>

using namespace std;

struct Student
{
	string name;
	int exam;
	int assignment;
};


string readLine(istream& fin);
string getPassOrFailString(int m1, int m2);
Student* loadStudents(string filename, int& nStuds);
void saveStudents(string filename, Student* results, int nStuds);
void displayStudents(Student* results, int nStuds);
Student* addStudent(Student* results, Student newStudent, int& nStuds);

void main()
{
	Student* results;
	int nStudents = 0;
	string filename = "marks.txt";

	Student temp;
	string inStr;
	char choice;


	results = loadStudents(filename, nStudents);

	do
	{
		cout << "  a - add a student" << endl;
		cout << "  d - display students" << endl;
		cout << "  s - save students" << endl;
		cout << "  x - exit" << endl;
		cout << "Enter choice: ";
		cin >> inStr;

		if(inStr.length() == 0)
		{
			choice = 'e';
		}
		else
		{
			choice = inStr[0];

			if (choice >= 'A' && choice <= 'Z')
			{
				choice = choice - 'A' + 'a';
			}
		}

		switch(choice)
		{
		case 'a':
			cout << "Enter name: ";
			temp.name = readLine(cin);
			cout << "Enter exam mark: ";
			cin >> temp.exam;
			cout << "Enter assignment mark: ";
			cin >> temp.assignment;
			results = addStudent(results, temp, nStudents);
			break;
		case 'd':
			displayStudents(results, nStudents);
			break;
		case 's':
			saveStudents(filename, results, nStudents);
			break;
		case 'x':
			break;
		default:
			cout << "Invalid choice" << endl;
			break;
		}
	}
	while(choice != 'x');

	delete [] results;
}

Student* loadStudents(string filename, int& nStuds)
{
	Student temp[100];
	Student* returnArray;
	bool earlyEof;

	ifstream inFile(filename.c_str());

	if(!inFile)
	{
		cout << "File not found" << endl;
		return 0;
	}
	else
	{
		nStuds = 0;
		while(!inFile.eof())
		{
			temp[nStuds].name = readLine(inFile);
			inFile >> temp[nStuds].exam;
			earlyEof = inFile.eof();
			inFile >> temp[nStuds].assignment;

			if (!earlyEof)
			{
				nStuds++;
			}
		}
		inFile.close();

		returnArray = new Student[nStuds];
		for(int i = 0; i<nStuds; i++)
		{
			returnArray[i] = temp[i];
		}
	}

	return returnArray;
}

Student* addStudent(Student* results, Student newStudent, int& nStuds)
{
	Student* temp = new Student[nStuds + 1];

	for(int i = 0; i<nStuds; i++)
	{
		temp[i] = results[i];
	}

	temp[nStuds] = newStudent;

	nStuds++;

	delete [] results;


	return temp;
}

void saveStudents(string filename, Student* results, int nStuds)
{
	ofstream outFile(filename.c_str());

	if(!outFile)
	{
		cout << "File can't be opened" << endl;
	}
	else
	{
		for(int i = 0; i<nStuds; i++)
		{
			outFile << results[i].name << endl;
			outFile << results[i].exam << endl;
			outFile << results[i].assignment << endl;
		}
		outFile.close();
	}
}

void displayStudents(Student* results, int nStuds)
{
	for(int i = 0; i<nStuds; i++)
	{
		cout << results[i].name << " " ;
		cout << " exam - " << results[i].exam;
		cout << " assignment - " << results[i].assignment;
		cout << " average - " << ((double)results[i].assignment+ results[i].exam)/2;
		cout << " " << getPassOrFailString(results[i].assignment, results[i].exam) << endl;
	}
}

string getPassOrFailString(int m1, int m2)
{
	if(m1 >= 30 && m2 >= 30 && (m1+m2)/2 >= 40)
	{
		return "pass";
	}
	else
	{
		return "fail";
	}
}


string readLine(istream& fin)
{
	char buff[256];

	if(fin.peek()=='\n')
	{
		fin.ignore();
	}
	fin.getline(buff, 256, '\n');
	return string(buff);
}
2
Contributors
1
Reply
2
Views
8 Years
Discussion Span
Last Post by Narue
0

Why are you trying to convert to a static array? The dynamic array is much more flexible, seeing as how you don't know how many records will be read from the file. It seems to me that you're taking a giant step backward in robustness.

You might notice this robustness if your loadStudents function actually bothered to take into account a variable number of records without forcing an upper limit. Try something more like this:

Student *loadStudents ( string filename, int& nStuds )
{
  ifstream in ( filename );
  Student *result = 0;

  nStuds = 0;

  if ( in ) {
    Student temp;

    // Assuming you add an overloaded 
    // operator<< to the Student class
    while ( in>> temp )
      ++nStuds;

    in.clear();
    in.seekg ( 0, ios::beg );

    result = new Student[nStuds];

    for ( int i = 0; in>> temp && i < nStuds; i++ )
      result[i] = temp;
  }

  return result;
}

This function reads the file twice: first to get the number of records, then to get store the records themselves after memory has been allocated. It's more tedious, memory management-wise, to grow a dynamic array as you fill it, which is one reason why the std::vector class exists.

You can avoid both by changing the format of the file to hold the number of records as the first line:

Student *loadStudents ( string filename, int& nStuds )
{
  ifstream in ( filename );
  Student *result = 0;

  nStuds = 0;

  if ( in ) {
    Student temp;

    in>> nStuds;
    result = new Student[nStuds];

    for ( int i = 0; in>> temp && i < nStuds; i++ )
      result[i] = temp;
  }

  return result;
}

Though using std::vector is by far the most recommended solution.

This topic has been dead for over six months. Start a new discussion instead.
Have something to contribute to this discussion? Please be thoughtful, detailed and courteous, and be sure to adhere to our posting rules.