Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

Chanda

macrumors newbie
Original poster
Nov 10, 2008
12
0
Halifax, NS
I'm having problems sorting an array of structs read from a file. I have a menu to sort by student number, student gpa, student name, and to find the average gpa's. The sort by gpa and student number are working fine, I thought it would be the same idea for sorting but it won't work. Any ideas how I can get the sort by name to work properly?
Code:
int main()
{
	student s[MAXCLASSSZ];	//creats struct s[0], s[1]...s[MAXCLASSSZ -1]
	int n;					//counter for records
	char choice;			//user's choice from menu
	double gpa_average;		//local variable to hold calculated gpa average

	decimal_format(cout);
	//formates decimals nicely on the screen
	
	explain_program(cout);
	//tell user what program does
	
	ifstream fin;
	ofstream fout;			//internal name for output file
				//internal name for input file

	fin.open("stu.in");
	if(fin.fail())
	{
		cout << "\nInput file opening failed!";
		exit(1);	//terminate program execution
	}
	fout.open("stu.out");
	if(fout.fail())
	{
		cout << "\nOutput file opening failed!";
		exit (1);	//terminate program execution
	}
	decimal_format(fout);
	//formats decimals nicely in output file

	//document file output
	fout << "\nChanda Kolibas	KMSV0606"
		<< "\nAssignment #10	Question #1\n";
	
	explain_program(fout);
	//write to file what program does
	
	read_array_of_struct(fin, s, n);
	//reads student file information
	
	print_menu(cout);
	//prints menu choices
	
	choice = get_choice();
	
	while(choice != QUIT)
	{
		switch(toupper(choice))
		{
		case '0': 
			print_menu(cout);
			break;
		case '1': 
			sort_on_name(s, n);
			cout << "\nSorted by name: \n\n";
			fout << "\nSorted by name: \n\n";
			write_array_of_struct(cout, s, n);
			write_array_of_struct(fout, s, n);
			break;
		case '2': 
			sort_on_student_number(s, n);
			cout << "\nSorted by student number: \n\n";
			fout << "\nSorted by student number: \n\n";
			write_array_of_struct(cout, s, n);
			write_array_of_struct(fout, s, n);
			break;
		case '3': 
			sort_on_gpa(s, n);
			cout << "\nSorted by gpa: \n\n";
			fout << "\nSorted by gpa: \n\n";
			write_array_of_struct(cout, s, n);
			write_array_of_struct(fout, s, n);
			break;
		case '4': 
			gpa_average = average_cal(s, n);
			cout << "\nThe average of all the GPA's is " << gpa_average << ".";
			fout << "\nThe average of all the GPA's is " << gpa_average << ".";
			break;
		default: 
			cout << "Sorry, " << choice << " is invalid."
				 << "\nPlease try again.";
		}
		choice = get_choice();
	}

	fin.close();
	fout.close();

	return 0;
}
void explain_program(ostream& os)
{
	os << "This program gives the user a menu of options.\n";
}

void decimal_format(ostream& os)
{
	os.setf(ios::fixed);
	os.setf(ios::showpoint);
	os.precision(2);
}


void read_array_of_struct(istream& is, student s[], int& n)
{
	char temp[MAXNAMESZ],	//temp storage for name
		 ch;		//char used to read <eoln>
	n = 0;			//no records have been read yet

	is.get(temp, MAXNAMESZ);
	while((!is.eof()) && ( n < MAXNAMESZ))
	{
		strcpy_s(s[n].name, temp); 
		is >> s[n].student_number;
		is >> s[n].gpa;
		is.get(ch);
		n++;
		is.get (temp, MAXNAMESZ);
	}
}
void write_array_of_struct(ostream& os, student s[], int& n)
{
	for(int i = 0; i < n; i++)
	{
		os << s[i].name;
		os.width(2);
		os << s[i].student_number;
		os.width(10);
		os << s[i].gpa << endl;
	}
}

void print_menu(ostream& os)
{
	os << "\n0 - See Menu Again";
	os << "\n1 - Sort by Name";
	os << "\n2 - Sort by Student Number";
	os << "\n3 - Sort by GPA";
	os << "\n4 - Find Average GPA";
	os << "\nQ - Quit this program\n\n\n";
}

char get_choice()
{
	char answer;	//local variable for choice storage
	cout << "\nPlease enter your choice (0 to see menu again, Q to exit program): ";
	cin >> answer;
	return answer;
}

void sort_on_name(student s[], int n)
{
	student temp;
	int pass;
	
	for(pass = 1; pass <= n-1; pass++);
	{
		for(int i = 0; i < n-pass; i++)
		{
			if(strcmp(s[i].name, s[i+1].name)>0)
			{
				temp = s[i];
				s[i] = s[i+1];
				s[i+1] = temp;
			}
		}
	}
}
void sort_on_student_number(student s[], int n)
{
	student temp;
	int pass;
	
	for(pass = 1; pass <= n-1; pass++)
	{
		for(int i = 0; i < n-pass; i++)
		{
			if(s[i].student_number > s[i+1].student_number)
			{
				temp = s[i];
				s[i] = s[i+1];
				s[i+1] = temp;
			}
		}
	}
}

void sort_on_gpa(student s[], int n)
{
	int i;
	student temp;
	
	for(int pass = 1; pass <= n-1; pass++)
	{
		for(i = 0; i < n-pass; i++)
		{
			if(s[i].gpa > s[i+1].gpa)
			{
				temp = s[i];
				s[i] = s[i + 1];
				s[i + 1] = temp;
			}
		}
	}
}

double average_cal(student s[], int n)
{
	double sum = 0,    //local variable for sum calculation
		   av;	//local variable for average calculation

	for(int i = 0; i < n; i++)
	{
		sum = sum + s[i].gpa;
	}
	av = sum/n;
	return av;
}
 

lee1210

macrumors 68040
Jan 10, 2005
3,182
3
Dallas, TX
Is this for a class?

Are you familiar with qsort?

The current sorting method is very inefficient. If you have to do it this way for a class, say so and we may be able to give you pointers, though painful.

-Lee
 

Chanda

macrumors newbie
Original poster
Nov 10, 2008
12
0
Halifax, NS
This is for a class, my prof. specifically requested a bubble sort (unfortunately). I know it's not the most efficient way to do it, but I have no choice :mad:. So, I'm doing my best, but can't seem to get it to work.
 

toddburch

macrumors 6502a
Dec 4, 2006
748
0
Katy, Texas
And the other #include files. I get 54 errors and 33 warnings I'm not interesting in looking at. ;)

(edit - no, it's a CPP file - I get 68 errors, no warnings. I don't know if that's better or worse!!)
 

Chanda

macrumors newbie
Original poster
Nov 10, 2008
12
0
Halifax, NS
Is this what you meant? The top portion of the code?

Code:
#include <iostream>			//provides cout, etc
#include <fstream>			//provides file input, output, etc
#include <cstdlib>			//provides exit
#include <cstring>			//provides strings
#include <cctype>			//provides toupper function
using namespace std;

const int MAXNAMESZ = 27;	//no more than 26 + '\0' in name
const int MAXCLASSSZ = 50;	//no more than 50 records in struct
const char QUIT = 'Q';		//user enters Q to exit program

struct student
{
	char name[MAXNAMESZ];
	int student_number;
	double gpa;
};

void explain_program(ostream& os);
//tells user what the program does

void decimal_format(ostream& os);
//formats decimals nicely in output stream os

void read_array_of_struct(istream& is, student s[], int& n);
//Precondition:  s[] has n valid records, no more than capacity
//Postcondition: these values are read from an input file

void write_array_of_struct(ostream& os, student s[], int& n);
//writes values

void print_menu(ostream& os);
//Postcondition:  The menu options are printed to the screen

char get_choice();
//Postcondition:  user's choice is returned

void sort_on_name(student s[], int n);
//Precondition:  s[] has n valid records
//These records are sorted by name

void sort_on_student_number(student s[], int n);
//Precondition: s[] has n valid records
//These records are sorted by student number

void sort_on_gpa(student s[], int n);
//Precondition: s[] has n valid records
//These records are sorted by gpa

double average_cal(student s[], int n);
//Precondition: s has n valid records
//Postcondition: the average gpa is returned

int main()
{
	student s[MAXCLASSSZ];	//creats struct s[0], s[1]...s[MAXCLASSSZ -1]
	int n;					//counter for records
	char choice;			//user's choice from menu
	double gpa_average;		//local variable to hold calculated gpa average

	decimal_format(cout);
	//formates decimals nicely on the screen
	
	explain_program(cout);
	//tell user what program does
	
	ifstream fin;
	ofstream fout;			//internal name for output file
				//internal name for input file

	fin.open("stu.in");
	if(fin.fail())
	{
		cout << "\nInput file opening failed!";
		exit(1);	//terminate program execution
	}
	fout.open("stu.out");
	if(fout.fail())
	{
		cout << "\nOutput file opening failed!";
		exit (1);	//terminate program execution
	}
	decimal_format(fout);
	//formats decimals nicely in output file

	//document file output
	fout << "\nChanda Kolibas	KMSV0606"
		<< "\nAssignment #10	Question #1\n";
	
	explain_program(fout);
	//write to file what program does
	
	read_array_of_struct(fin, s, n);
	//reads student file information
	
	print_menu(cout);
	//prints menu choices
	
	choice = get_choice();
	
	while(choice != QUIT)
	{
		switch(toupper(choice))
		{
		case '0': 
			print_menu(cout);
			break;
		case '1': 
			sort_on_name(s, n);
			cout << "\nSorted by name: \n\n";
			fout << "\nSorted by name: \n\n";
			write_array_of_struct(cout, s, n);
			write_array_of_struct(fout, s, n);
			break;
		case '2': 
			sort_on_student_number(s, n);
			cout << "\nSorted by student number: \n\n";
			fout << "\nSorted by student number: \n\n";
			write_array_of_struct(cout, s, n);
			write_array_of_struct(fout, s, n);
			break;
		case '3': 
			sort_on_gpa(s, n);
			cout << "\nSorted by gpa: \n\n";
			fout << "\nSorted by gpa: \n\n";
			write_array_of_struct(cout, s, n);
			write_array_of_struct(fout, s, n);
			break;
		case '4': 
			gpa_average = average_cal(s, n);
			cout << "\nThe average of all the GPA's is " << gpa_average << ".";
			fout << "\nThe average of all the GPA's is " << gpa_average << ".";
			break;
		default: 
			cout << "Sorry, " << choice << " is invalid."
				 << "\nPlease try again.";
		}
		choice = get_choice();
	}

	fin.close();
	fout.close();

	return 0;
}
void explain_program(ostream& os)
{
	os << "This program gives the user a menu of options.\n";
}

void decimal_format(ostream& os)
{
	os.setf(ios::fixed);
	os.setf(ios::showpoint);
	os.precision(2);
}


void read_array_of_struct(istream& is, student s[], int& n)
{
	char temp[MAXNAMESZ],	//temp storage for name
		 ch;				//char used to read <eoln>
	n = 0;					//no records have been read yet

	is.get(temp, MAXNAMESZ);
	while((!is.eof()) && ( n < MAXNAMESZ))
	{
		strcpy_s(s[n].name, temp); 
		is >> s[n].student_number;
		is >> s[n].gpa;
		is.get(ch);
		n++;
		is.get (temp, MAXNAMESZ);
	}
}
void write_array_of_struct(ostream& os, student s[], int& n)
{
	for(int i = 0; i < n; i++)
	{
		os << s[i].name;
		os.width(2);
		os << s[i].student_number;
		os.width(10);
		os << s[i].gpa << endl;
	}
}

void print_menu(ostream& os)
{
	os << "\n0 - See Menu Again";
	os << "\n1 - Sort by Name";
	os << "\n2 - Sort by Student Number";
	os << "\n3 - Sort by GPA";
	os << "\n4 - Find Average GPA";
	os << "\nQ - Quit this program\n\n\n";
}

char get_choice()
{
	char answer;	//local variable for choice storage
	cout << "\nPlease enter your choice (0 to see menu again, Q to exit program): ";
	cin >> answer;
	return answer;
}

void sort_on_name(student s[], int n)
{
	student temp;
	int pass;
	
	for(pass = 1; pass <= n-1; pass++);
	{
		for(int i = 0; i < n-pass; i++)
		{
			if(strcmp(s[i].name, s[i+1].name)>0)
			{
				temp = s[i];
				s[i] = s[i+1];
				s[i+1] = temp;
			}
		}
	}
}
void sort_on_student_number(student s[], int n)
{
	student temp;
	int pass;
	
	for(pass = 1; pass <= n-1; pass++)
	{
		for(int i = 0; i < n-pass; i++)
		{
			if(s[i].student_number > s[i+1].student_number)
			{
				temp = s[i];
				s[i] = s[i+1];
				s[i+1] = temp;
			}
		}
	}
}

void sort_on_gpa(student s[], int n)
{
	int i;
	student temp;
	
	for(int pass = 1; pass <= n-1; pass++)
	{
		for(i = 0; i < n-pass; i++)
		{
			if(s[i].gpa > s[i+1].gpa)
			{
				temp = s[i];
				s[i] = s[i + 1];
				s[i + 1] = temp;
			}
		}
	}
}

double average_cal(student s[], int n)
{
	double sum = 0, //local variable for sum calculation
		   av;		//local variable for average calculation

	for(int i = 0; i < n; i++)
	{
		sum = sum + s[i].gpa;
	}
	av = sum/n;
	return av;
}
 

toddburch

macrumors 6502a
Dec 4, 2006
748
0
Katy, Texas
lol. Yeah, that's what I meant. (try commenting all that out and compiling and you'll see what I mean.)

Did you copy this over from MS VC++? I see a strcpy_s (safe) function is barking at me.
 

toddburch

macrumors 6502a
Dec 4, 2006
748
0
Katy, Texas
To start with, consider putting the is.get() inside the loop.

Code:
void read_array_of_struct(istream& is, student s[], int& n)
{
	char temp[MAXNAMESZ],	//temp storage for name
		 ch;		//char used to read <eoln>
	n = 0;			//no records have been read yet

	[color=red]is.get(temp, MAXNAMESZ);[/color]
	while((!is.eof()) && ( n < MAXNAMESZ))
	{
		strcpy(s[n].name, temp); 
		is >> s[n].student_number;
		is >> s[n].gpa;
		is.get(ch);
		n++;
		is.get (temp, MAXNAMESZ);
	}
 

Chanda

macrumors newbie
Original poster
Nov 10, 2008
12
0
Halifax, NS
I have it before the loop and at the end of the loop (lol, just like I was taught!). Anyway, that's not the part I'm having trouble with, it's only the sort_on_name() function that's giving me problems (I managed to get the rest of it to work).
 

toddburch

macrumors 6502a
Dec 4, 2006
748
0
Katy, Texas
You are correct. I don't code like that, but whatever you gotta do, you gotta do.

An error still lies in this routine however. Only Jan Jones is getting read in and none of the other records are brought in properly.
Code:
void read_array_of_struct(istream& is, student s[], int& n)
{
	char temp[MAXNAMESZ],	//temp storage for name
		 ch;		//char used to read <eoln>
	n = 0;			//no records have been read yet

	is.get(temp, MAXNAMESZ);
	while((!is.eof()) && ( n < [color=red]MAXNAMESZ[/color]))  // should be MAXCLASSSZ, not name size 
	{
		strcpy(s[n].name, temp); 
		is >> s[n].student_number;
		is >> s[n].gpa;
		is.get(ch);
		n++;
		is.get (temp, MAXNAMESZ);
	}

In the debugger, I can see the first record being assigned properly, but none of the rest. I suppose you ought to be passing the student struct as a reference instead of by value.
 

Chanda

macrumors newbie
Original poster
Nov 10, 2008
12
0
Halifax, NS
I'll give it a try in the morning. Thanks so much for your help! I've been stuck on this for days now. I normally wouldn't ask for help, I prefer to figure it out on my own, but that last bit was really giving me trouble.
 

lee1210

macrumors 68040
Jan 10, 2005
3,182
3
Dallas, TX
I worked through the read_array_of_struct. toddburch already pointed out that your limit is wrong. Other than that... well... i had to tweak it to clear until the end of a line. I don't know if what you have works on windows/VC++. I also switched strcpy_s to strncpy so it would compile w/ GCC. Once i got things reading (after having renamed the input file to what the code was expecting) the error was pretty clear. Take a look in your sort_on_name function closely. Note that a for, while, do, etc. loop will only run the expression that immediately follows the ) that closes the loop construct. That expression can be a block enclosed in {}, but if you end another expression with ;, the loop will only run that expression. A block is perfectly valid anywhere in your code, so one will run once if it's not the expression run by a loop.

You don't need XCode working to use your mac to develop. Learn to compile with gcc and debug with gdb from the command line. This will take you much further than learning VC++ or XCode.

-Lee
 

toddburch

macrumors 6502a
Dec 4, 2006
748
0
Katy, Texas
Here's a hint at what the file looks like. See that and you'll figure out what you need to do to fix your read_array... method:
Code:
0000: 4A 6F 6E 65 73 20 20 20 20 20 4A 61 6E 20 20 20 	Jones     Jan   
0010: 20 20 20 20 20 20 20 20 20 20 32 31 34 34 20 34 	          2144 4
0020: 2E 35 [color=green]0D[/color] [color=red]0A[/color] 41 64 61 6D 73 20 20 20 20 20 52 6F 	.5..Adams     Ro
0030: 62 65 72 74 20 20 20 20 20 20 20 20 20 20 36 35 	bert          65
0040: 35 30 20 33 2E 32 0D 0A 57 69 72 65 20 20 20 20 	50 3.2..Wire    
0050: 20 20 42 61 72 62 20 20 20 20 20 20 20 20 20 20 	  Barb          
0060: 20 20 39 37 32 34 20 33 2E 37 0D 0A 50 65 61 63 	  9724 3.7..Peac
0070: 65 20 20 20 20 20 57 61 72 72 65 6E 20 20 20 20 	e     Warren    
0080: 20 20 20 20 20 20 36 36 36 30 20 31 2E 33 0D 0A 	      6660 1.3..
0090: 54 79 6D 65 20 20 20 20 20 20 4A 75 73 74 69 6E 	Tyme      Justin
00A0: 20 20 20 20 20 20 20 20 20 20 31 32 36 31 20 34 	          1261 4
00B0: 2E 38 0D 0A 41 64 61 6D 73 20 20 20 20 20 44 6F 	.8..Adams     Do
00C0: 75 67 6C 61 73 20 20 20 20 20 20 20 20 20 39 38 	uglas         98
00D0: 36 36 20 33 2E 33 0D 0A 44 61 79 20 20 20 20 20 	66 3.3..Day     
00E0: 20 20 44 75 73 74 79 20 20 20 20 20 20 20 20 20 	  Dusty         
00F0: 20 20 36 35 39 31 20 33 2E 37 0D 0A 5A 75 62 61 	  6591 3.7..Zuba

0100: 20 20 20 20 20 20 4C 75 62 61 20 20 20 20 20 20 	      Luba      
0110: 20 20 20 20 20 20 32 37 37 37 20 33 2E 39 0D 0A 	      2777 3.9..
0120: 57 6F 6F 64 73 20 20 20 20 20 54 69 67 65 72 20 	Woods     Tiger 
0130: 20 20 20 20 20 20 20 20 20 20 34 34 34 34 20 34 	          4444 4
0140: 2E 30 0D 0A 53 69 6D 70 73 6F 6E 20 20 20 42 61 	.0..Simpson   Ba
0150: 72 74 20 20 20 20 20 20 20 20 20 20 20 20 35 38 	rt            58
0160: 34 39 20 31 2E 30 0D 0A                         	49 1.0..
 

Sander

macrumors 6502a
Apr 24, 2008
521
67
the error was pretty clear. Take a look in your sort_on_name function closely. Note that a for, while, do, etc. loop will only run the expression that immediately follows the ) that closes the loop construct. That expression can be a block enclosed in {}, but if you end another expression with ;, the loop will only run that expression. A block is perfectly valid anywhere in your code, so one will run once if it's not the expression run by a loop.

If you still don't see it after lee's thorough explanation, maybe one final hint: an "empty" expression is an expression, too.
 

Chanda

macrumors newbie
Original poster
Nov 10, 2008
12
0
Halifax, NS
I guess I was just too tired to catch it last night, thanks for all your hints and help. Everything is now sorting as it should. Although in my defense, it is difficult to see one little semi-colon is in the wrong place when there are so many more to check for. :) Next time I'll be sure to look for placement of brackets and semi-colons more carefully!

Oh, and I did adjust the limit to read correctly (just hadn't done it to the piece I posted). Thanks again for everything!

~Chanda
 

Catfish_Man

macrumors 68030
Sep 13, 2001
2,579
2
Portland, OR
GCC really needs a warning about that, I have to say. I've had it happen at least a half dozen times and it's very confusing. I suppose it'd have to be optional in case someone's favored coding style used for(); instead of for() {} for intentionally empty loops, but so it goes.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.