c++arraysstructqsort

Address boundary error when sorting an array of structs


I am working through a book called "Think Like a Programmer." Chapter 2 is about solving problems with arrays. There's an exercise at the end of the chapter that asks us to use qsort to sort a an array of structs created earlier in the chapter.

Following the process of the chapter, I created a function, comparator that will be passed to qsort to sort the array, studentArray. My code is...working? However, I'm getting an Address boundary error when running it.

#include <string>
#include <iostream>

using std::cout;
using std::string;

int comparator(const void * voidA, const void * voidB) {
  int * intA = (int *)(voidA);
  int * intB = (int *)(voidB);

  return *intA - *intB;
}

int main() {

  struct student {
    int grade;
    int studentID;
    string name;
  };

  const int ARRAY_SIZE = 10; 

  student studentArray[ARRAY_SIZE] = {
    {87, 10001, "Fred"},
    {28, 10002, "Tom"},
    {100, 10003, "Alistair"},
    {78, 10004, "Sasha"},
    {84, 10005, "Erin"},
    {98, 10006, "Belinda"},
    {75, 10007, "Leslie"},
    {70, 10008, "Candy"},
    {81, 10009, "Aretha"},
    {68, 10010, "Veronica"},
  };

  qsort(studentArray, ARRAY_SIZE, sizeof(student), comparator);

  for (int i = 0; i < ARRAY_SIZE; i++) {
    cout << studentArray[i].grade << "\n";
  }
}

My first assumption was that I messed up the call to qsort with the third parameter. Maybe, I thought, I should only be asking for the size of the first member of the struct (since that's what the first part of the exercise asks us to sort). So, I changed it to:

qsort(studentArray, ARRAY_SIZE, sizeof(student[0]), comparator);

This didn't throw any errors, but it didn't sort the array either. So, all in all, I think I'm just confused about what I'm doing wrong. I don't work with C++ regularly, it's just for the purpose of the book. However, I am really enjoying using it and learning about it, so I would like to understand what causes this problem*. I have searched around online for a while and have seen similar asks, but I can't seem to piece together a solid understanding. I will update this post with any missing information; please just let me know what's needed. I appreciate any and all help with this and hope that it makes sense.

As stated above, I tried a few different things (some of which I'm too embarrassed to mention here).

EDIT: I appreciate the comments and the resources! I'll add one more question to this post: are the concepts taught in the book so closely coupled with the author's C++ implementation that one wouldn't be able to understand what causes this error without a proper understanding of modern C++? Thanks again!


Solution

  • For comparison if your book was more current code would look like this - as you see you can use a custom compare function as argument to sort.

    #include <algorithm> // for sort.
    #include <string>
    #include <iostream>
    #include <vector>
    
    //using std::cout;
    //using std::string;
    
    /*
    int comparator(const void* voidA, const void* voidB) {
        int* intA = (int*)(voidA);
        int* intB = (int*)(voidB);
    
        return *intA - *intB;
    }
    */
    
    struct student 
    {
        int grade;
        int studentID;
        std::string name;
    };
    
    bool compare_students_by_grade(const student& lhs, const student& rhs)
    {
        return lhs.grade < rhs.grade;
    }
    
    int main() 
    {
        std::vector<student> students = // avoid types in your names
        {
          {87, 10001, "Fred"},
          {28, 10002, "Tom"},
          {100, 10003, "Alistair"},
          {78, 10004, "Sasha"},
          {84, 10005, "Erin"},
          {98, 10006, "Belinda"},
          {75, 10007, "Leslie"},
          {70, 10008, "Candy"},
          {81, 10009, "Aretha"},
          {68, 10010, "Veronica"},
        };
    
        //qsort(studentArray, ARRAY_SIZE, sizeof(student), comparator);
        std::sort(students.begin(), students.end(), compare_students_by_grade); 
    
        /*
        for (int i = 0; i < ARRAY_SIZE; i++) {
            cout << studentArray[i].grade << "\n";
        }
        */
    
        // prefer range based for loops, they cannot go out of range
        for (const student& student : students)
        {
            std::cout << student.name << " has grade : " << student.grade << "\n";
        }
    
        return 0;
    }
    

    student& is a reference to an instance of student (kind of like a pointer that must be valid al the time)