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);
}

Dani AI

Generated

A quick, practical way to satisfy the “static array” requirement while keeping the rest of the program logic intact is to pick a sensible maximum and treat the array as a fixed-capacity container with a separate count. That means: declare Student results[MAX] (or std::array<Student, MAX>), keep an int nStudents counter, and stop adding when nStudents == MAX. This removes the need for new[]/delete[], but you must explicitly guard against overflow and be aware of where the array is stored (large arrays on the stack can cause problems).

Example pattern:

const int MAX_STUDENTS = 200;
Student results[MAX_STUDENTS];
int nStudents = 0;

// adding a new student
if (nStudents < MAX_STUDENTS)
    results[nStudents++] = newStudent;
else
    cerr << "student list full\n";

When converting the file I/O functions, change signatures so they operate on the caller-provided array (e.g., bool loadStudents(const string& filename, Student results[], int& nStudents)) and make the loader refuse to exceed MAX_STUDENTS. Replace while(!inFile.eof()) with a robust read pattern: read a name line with getline, then read the two marks with operator>>, verify both reads succeeded before incrementing nStudents, and handle the newline left in the stream when mixing getline and >>. Also change void main() to int main() and return 0.

Tradeoffs and cautions: a static array fixes memory usage and is simple, but it loses flexibility and can silently truncate data if MAX_STUDENTS is too small. If the data set might grow or you want safer, simpler code, ’s point about using a container like std::vector (or std::array for truly fixed size) is still the best long-term choice.

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.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.