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!
CodePudding user response:
For comparisson 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)
CodePudding user response:
As mentioned in a comment, your comaprator pretends that the pointers it gets passed are pointers to int
but they are pointers to student
. Use std::sort
:
#include <string>
#include <iostream>
#include <algorithm>
using std::cout;
using std::string;
struct student {
int grade;
int studentID;
string name;
};
bool comparator(const student& a, const student& b) {
return a.grade < b.grade;
}
int main() {
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"},
};
std::sort(std::begin(studentArray),std::end(studentArray),comparator);
for (int i = 0; i < ARRAY_SIZE; i ) {
cout << studentArray[i].grade << "\n";
}
}
Here, the comparator is type safe, using wrong types would result in a compiler error. Also, you need not manually specify the number of elements or their size.
Note, that this answer illustrates how to change your code for more idomatic C . The code presented here on the other hand is only replacing qsort
and minimum changes otherwise.