Hi,

I'm a beginning C++ student and have an assignment to dynamically create an array of a struct to store students' first names, last names, and test grade scores, and then pass it via pointer to a function that will sort the grades and names in ascending order. I wrote a function that finds the lowest numeric grade score of the pointer array of struct, puts it in the first (0) index position, and then puts the numeric value that was in the first (0) index position in the index position that was formerly occupied by the newly found lowest value. Then, it starts at the next highest index position and finds the next lowest value, etc, and swaps it. The issue that I'm having is that I can get the numeric scores sorted properly and moved in the function, but I can't get the first and last names in the array to change position, except somewhat unpredictably. Sometimes, one of the names will overwrite another name and be listed twice in the final output. I have them declared as a string data type and ideally would like them to do the same thing that I have the numeric values doing, but can't seem to achieve it. I've tried using char and strcpy but that's not working, either. I'm sure there's an easier way to do what I'm doing but the assignment is worded very specifically. I'm not sure if it's a simple logic error in the nested loop or perhaps I need to use a different syntax or method to change the index positions of the strings, since I'm using pointers? Maybe a constructor for struct?

This is my first post on any C++ forum, so please excuse any transgressions I may have made in code etiquette, posting, etc! I read all the faqs first and tried to follow them as much as possible, so my apologies if I shouldn't have posted the whole code- I just wanted to give a clear idea of the problem! I'd really appreciate any help...

Thanks in advance!
Evan

/* Test Scores #2 programming challenge */

#include <iostream>
#include <iomanip>
#include <string>
#include <cstring>
using namespace std;

struct TestData //create TestData structure to hold students' first name, last name, and grade score
{
	string studentFirstName;
	string studentLastName;
	float studentGrade;
};

typedef struct TestData StructDataType; //create a data type StructDataType to be able pass the entire
										//structure back and forth by pointers
StructDataType *getScores(int ); //function prototype to dynamically create a pointer array of struct with data
								 //type of StructDataType to be able to input mixed string/int values into the array,
								 //then pass it back into int main by using pointers
void structSort(StructDataType *, int); //function prototype to sort the pointer array of struct by integer grade score,
										//then pass it back by pointer into int main
float findAverage(StructDataType *, int); //function prototype to find the average integer grade test score, passes again
										  //by use of pointers to and from findAverage function
void printScores(StructDataType *, int); //outputs resorted pointer array of struct

int main()
{
	int numScores;
	cout << "How many test scores would you like to enter? ";
	cin >> numScores;

	StructDataType *test1Scores = getScores(numScores); /*sets pointer array of data type StructDataType equal to results
														of calling function getScores, which dynamically creates an
														array and asks user to enter in required data */
	structSort(test1Scores, numScores); //calls function to perform selection sort by integer test score
	float averageScore = findAverage(test1Scores, numScores); /*sets float integer averageScore equal to results of function call
															  findAverage, which passes test1Scores array to function that finds
															  average of all test scores*/
	printScores(test1Scores, numScores); //function call to output resorted list to screen
	cout << "\nAverage test score in your array is: " << setprecision(3) << averageScore << endl << endl;
	cout << endl;
	system("pause");
	return 0;

}

StructDataType *getScores(int numScores)
{
	const int numChars = 20;
	StructDataType *test1Scores;
	while (numScores < 2)
	{
		cout << "Test score array can't be less than 2!\n" << "\nPlease enter a number " <<
			"2 or greater for test score array: "; //validate entries to be greater than 1 for array size
		cin >> numScores;
	}
	test1Scores = new StructDataType[numScores];
	for (int index = 0; index < numScores; index++) //for loop for user to enter input up to however many records are to be created
	{
		cout << "\nEnter student # " << index + 1 << " first name: ";
		cin >> test1Scores[index].studentFirstName; //enter first name for record in test1Scores array of struct
		cout << "Enter student # " << index + 1 << " last name: ";
		cin >> test1Scores[index].studentLastName; //enter last name for record in test1Scores array of struct
		cout << "Enter student # " << index + 1 << " test score: ";
		cin >> test1Scores[index].studentGrade; //enter grade score record in test1Scores array of struct
		while (test1Scores[index].studentGrade < 0 || test1Scores[index].studentGrade > 100) /*validate numeric test grade score entries
																							 to be greater than 0 and less than 101 */
		{
			cout << "Test score value can't be less than 0 or over 100!\n" << "\nPlease enter a value " <<
			"greater than -1 and less than 100 for test score " << index + 1 << ": ";
			cin >> test1Scores[index].studentGrade;
		}
	}
	return test1Scores;
}

void structSort(StructDataType *test1Scores, int numScores) /*function to perform selection sort based value of studentGrade, which is
															the float data variable to hold numeric test score */
{
	string tempFirstName, tempLastName;
	int startScan, minIndex;
	float minValue;  
	
	for (startScan = 0; startScan < numScores - 1; startScan++) //nested loops to find lowest value of studentGrade
	{
		minIndex = startScan;
		minValue = (test1Scores + startScan)->studentGrade;
		for (int index = startScan + 1; index < numScores; index++)
		{
			if ((test1Scores + index)->studentGrade < minValue)
			{
				minValue = (test1Scores + index)->studentGrade;
				minIndex = index;
			}
		}
		/*this is the issue! these statements are supposed to swap the numeric value of the lowest value of studentGrade found in the
		pointer struct array with the first position of the array's index, and also swap the first and last names of the new lowest
		score with the first and last names that were in index position 0.  i.e., if the lowest test grade score was at index position
		4, put it at position 0 along with the first and last names that were at that position, and put the old value of position 0 at
		position 4, along with the first and last names that were at position 0.  This is working with the numeric values perfectly
		but for some reason it's not working with with the string values for the students' first and last names.  I tried switching to
		char data type within the intial struct declaration and using strcpy and passing the array by reference (see below comments) but
		that's not working, either! */
		(test1Scores + minIndex)->studentFirstName = (test1Scores + startScan)->studentFirstName;
		(test1Scores + minIndex)->studentLastName = (test1Scores + startScan)->studentLastName;
		(test1Scores + minIndex)->studentGrade = (test1Scores + startScan)->studentGrade;
		(test1Scores + startScan)->studentGrade = minValue;
		//strcpy(&test1Scores[startScan].studentFirstName, &test1Scores[minValue].studentFirstName);
		//strcpy(&test1Scores[startScan].studentLastName, &test1Scores[minValue].studentLastName);
	}
}

float findAverage(StructDataType *test1Scores, int numScores)
{
	float total = 0, average;

	for (int index = 0; index < numScores; index ++)
	{
		total += (test1Scores+index)->studentGrade;
	}

	average = total / numScores;
	return average;
}

void printScores(StructDataType *test1Scores, int numScores)
{
	for (int index = 0; index < numScores; index++)
	{
		cout << "\n" << (test1Scores+index)->studentLastName << ", "
			<< (test1Scores+index)->studentFirstName << ": " << (test1Scores+index)->studentGrade;
	}
	cout << endl;
}

I wrote a function that finds the lowest numeric grade score of the pointer array of struct, puts it in the first (0) index position, and then puts the numeric value that was in the first (0) index position in the index position that was formerly occupied by the newly found lowest value.

[3][2][1][0]
[0][2][1][3]
...

Then, it starts at the next highest index position and finds the next lowest value, etc, and swaps it.

[3][2][1][0]
[0][2][1][3]
[0][1][2][3]

So it appears to be algorithmically sound assuming you implement it properly :)

The issue that I'm having is that I can get the numeric scores sorted properly and moved in the function, but I can't get the first and last names in the array to change position, except somewhat unpredictably.

The best advice I have for you is to run your code under a debugger and see for yourself what is happening. If you're using Visual Studio be sure to "start debugging" and set some breakpoints to examine the contents of your variables.
If you don't know what I mean I will make a youtube video of it and link you to it, but who knows when that will be.

Found the fix thanks to a classmate- posting it here so maybe someone else can benefit!

replace this section in my code (actual line numbers 105-110 in my original post):

(test1Scores + minIndex)->studentFirstName = (test1Scores + startScan)->studentFirstName;
(test1Scores + minIndex)->studentLastName = (test1Scores + startScan)->studentLastName;
(test1Scores + minIndex)->studentGrade = (test1Scores + startScan)->studentGrade;
(test1Scores + startScan)->studentGrade = minValue;

with below single line of code:

swap(test1Scores[startScan], test1Scores[minIndex]);

Apparently, you can swap out one whole record array of struct using the "swap" command instead of having to do each item individually, as I was trying to do!

Evan

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.