-2

I'll admit I'm completely stumped. This is one of those bugs you will only get from a language like c++.

I've got a struct array that I am modifying the member data for. Just normal assignment really. I've got one function that gets some of the member data, the function then calls another function which will get other member data. When I use the Visual Studio debugger to step through, all the assignment seems to go by fine. I watch the variables change in the debugging window at the bottom. But once the second function goes back up to the calling function, the data vanishes. it goes back to unallocated gibberish. Any Idea's?

Edit: Do not mark this question as a duplicate of a value/reference discussion. It should either be deleted for uniqueness, or left alone. Far too many answers on this site are marked as duplicate simply because an answer somewhere else might answer the question, even though the questions are different. If the questions are different, they should be separate.

The two functions:

void GetTestData(Student* students, int numStudents, int numTests)
{
  // Loop through the i students and all j tests
  for (int i = 0; i < numStudents; ++i)
  {
    // get test scores
    for (int j = 0; j < numTests; ++j)
    {
        cout << "What was " + students[i].Name + "'s score for test #" + to_string(j + 1) + "? ";
        cin >> students[i].Tests[j];
    }

    CalcGrades(students[i], numTests);
  }
}

void CalcGrades(Student student, int numTests)
{
  double sum = 0;

  // add up all the scores
  for (int i = 0; i < numTests; ++i)
  {
    sum += student.Tests[i];
  }

  // calculate the average and store it in the members
  student.Avg = sum / numTests;

  // grade assignment tree
  if (student.Avg >= 91)
  {
    student.Grade = 'A';
  }
  else if (student.Avg >= 81)
  {
    student.Grade = 'B';
  }
  else if (student.Avg >= 71)
  {
    student.Grade = 'C';
  }
  else if (student.Avg >= 61)
  {
    student.Grade = 'D';
  }
  else
  {
    student.Grade = 'F';
  }
}

2 Answers2

2

The problem here as @James Root has said is passing by reference vs passing by value. After you make the change to the Student, pass it back to the array.

Student* GetTestData(Student* students, int numStudents, int numTests)
{
  // Loop through the i students and all j tests
  for (int i = 0; i < numStudents; ++i)
  {
    // get test scores
    for (int j = 0; j < numTests; ++j)
    {
        cout << "What was " + students[i].Name + "'s score for test #" + to_string(j + 1) + "? ";
        cin >> students[i].Tests[j];
    }

    students[i] = CalcGrades(students[i], numTests); //after the value was changed, store it in the array
  }
  return students;
}

Student CalcGrades(Student student, int numTests)
{
  double sum = 0;

  // add up all the scores
  for (int i = 0; i < numTests; ++i)
  {
    sum += student.Tests[i];
  }

  // calculate the average and store it in the members
  student.Avg = sum / numTests;

  // grade assignment tree
  if (student.Avg >= 91)
  {
    student.Grade = 'A';
  }
  else if (student.Avg >= 81)
  {
    student.Grade = 'B';
  }
  else if (student.Avg >= 71)
  {
    student.Grade = 'C';
  }
  else if (student.Avg >= 61)
  {
    student.Grade = 'D';
  }
  else
  {
    student.Grade = 'F';
  }
  return student;
}
obl
  • 1,799
  • 12
  • 38
1

The best solution is to move the call to CalcGrades outside of the loop in GetTestData, and rewrite it to be a full loop through all Students like the other functions. This sidesteps the shortcomings of pointers.