sorting arrays of structs

Discussion in 'Mac Programming' started by Chanda, Nov 25, 2008.

  1. Chanda macrumors newbie

    Joined:
    Nov 10, 2008
    Location:
    Halifax, NS
    #1
    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;
    }
    
     
  2. toddburch macrumors 6502a

    Joined:
    Dec 4, 2006
    Location:
    Katy, Texas
    #2
    Post a copy of your input file and I'll help you debug it.
     
  3. lee1210 macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #3
    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
     
  4. Chanda thread starter macrumors newbie

    Joined:
    Nov 10, 2008
    Location:
    Halifax, NS
    #4
    This is the file I'm using (attached text file)
     

    Attached Files:

    • stu.txt
      File size:
      360 bytes
      Views:
      31
  5. Chanda thread starter macrumors newbie

    Joined:
    Nov 10, 2008
    Location:
    Halifax, NS
    #5
    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.
     
  6. toddburch macrumors 6502a

    Joined:
    Dec 4, 2006
    Location:
    Katy, Texas
    #6
    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!!)
     
  7. Chanda thread starter macrumors newbie

    Joined:
    Nov 10, 2008
    Location:
    Halifax, NS
    #7
    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;
    }
    
     
  8. toddburch macrumors 6502a

    Joined:
    Dec 4, 2006
    Location:
    Katy, Texas
    #8
    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.
     
  9. Chanda thread starter macrumors newbie

    Joined:
    Nov 10, 2008
    Location:
    Halifax, NS
    #9
    Yes, I can't figure out XCode C++ compiler, so I use MS VC++ for school.
     
  10. toddburch macrumors 6502a

    Joined:
    Dec 4, 2006
    Location:
    Katy, Texas
    #10
    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);
    	}
    
     
  11. Chanda thread starter macrumors newbie

    Joined:
    Nov 10, 2008
    Location:
    Halifax, NS
    #11
    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).
     
  12. toddburch macrumors 6502a

    Joined:
    Dec 4, 2006
    Location:
    Katy, Texas
    #12
    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.
     
  13. Chanda thread starter macrumors newbie

    Joined:
    Nov 10, 2008
    Location:
    Halifax, NS
    #13
    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.
     
  14. lee1210 macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #14
    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
     
  15. toddburch macrumors 6502a

    Joined:
    Dec 4, 2006
    Location:
    Katy, Texas
    #15
    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..
    
     
  16. Sander macrumors 6502

    Joined:
    Apr 24, 2008
    #16
    If you still don't see it after lee's thorough explanation, maybe one final hint: an "empty" expression is an expression, too.
     
  17. Chanda thread starter macrumors newbie

    Joined:
    Nov 10, 2008
    Location:
    Halifax, NS
    #17
    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
     
  18. Catfish_Man macrumors 68030

    Catfish_Man

    Joined:
    Sep 13, 2001
    Location:
    Portland, OR
    #18
    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.
     

Share This Page