0

A class project involves sorting an array of strings, with each string containing an equal number of columns like this:

Cartwright   Wendy    93
Williamson   Mark     81
Thompson     Mark     100
Anderson     John     76
Turner       Dennis   56

The program accepts a command-line argument for which column to sort on, and should print out the sorted strings unmodified.

I would like to use strtok to break up copies of each string into columns, and make structs for each line like this:

struct line {
    char * line;
    char column_to_sort_on[MAX_COLUMN];
}

My problem is in the comparison function pointer that qsort takes as an arg. If I understand correctly, the comparison function must take two const void pointers to the items to be sorted, and return an int. This means I can't pass pointers to structs into the comparison function because that is not what qsort will be sorting. I can't pass in the column number to sort on to the comparison function, because it can only take two args. How can I get around this to sort these strings based on specific columns?

edit: Sorting is limited to qsort or my own if I really want. Give the choice, I choose qsort. :)

edit # 2:The consensus seems to be either use a global variable for the column number, or just use qsort to sort an array of structs. I hadn't thought of just sorting the structs, and using the pointer in them to print out the original string. I think that is what I will do. Thanks for the help all!

Mat
  • 202,337
  • 40
  • 393
  • 406
Jamison Dance
  • 19,896
  • 25
  • 97
  • 99
  • Does the assignment say you have to pass an array of strings to qsort, or that the as a result a string array must be sorted, no matter what it takes? If the latter, you could sort an array of structs, and then reorder the string array according to the results. – UncleBens Sep 19 '09 at 21:45

4 Answers4

2

Assuming you're not limited to using qsort, you can use std::sort, with a functor object that stores the column number. If you have to use qsort, one quick and dirty solution would be to store the column number in a global variable and use that in the comparisson function.

sepp2k
  • 363,768
  • 54
  • 674
  • 675
2

Different comparator functions, all of which take the whole struct, but each uses only one column for comparation.

Roberto Bonvallet
  • 31,943
  • 5
  • 40
  • 57
  • Wouldn't this comparator function necessitate sorting an array of structs? I though what I passed into the comparator function had to be the same as what qsort was sorting, and I would only like to sort the original array of strings. – Jamison Dance Sep 19 '09 at 20:08
2

You can pass the structs like this:

struct line {
    char * line;
    char column_to_sort_on[MAX_COLUMN];
}
...

line*  Lines[max_lines]; // here you store the structs

int
cmp_lines( const void *elem1, const void *elem2 )
{
    line*  line1 = *(line**)elem1;
    line*  line2 = *(line**)elem2;
    // do the comparisons
}

qsort(Lines, max_lines, sizeof(line*), cmp_lines);
Nick Dandoulakis
  • 42,588
  • 16
  • 104
  • 136
1

C++ or C? Based on your tags, I assume it's C++. Let's try STL way.

You should use std::sort instead of qsort. std::sort can take not only function pointer (compared to its C alternative), but any object that can be called as a function. You may know that class instances can be called as functions with operator(). Then the solution is straightforward: create a "functor" class that will create different functions upon construction. The sort call would then look like that:

std::sort(array, array+size, comparator(2 /* sort by column #2 */));

The functor class effectively creates a so-called "closure": a dynamically created functional object that has local variables, but doesn't share them with other functional objects created this way. It would look like this:

class comparator{
  private: unsigned int field_n;
  public: comparator(unsigned int _field_n) : field_n(_field_n) {};
  public: int operator () (char const *  lhs, char const * rhs)
       { /* compare here fields with index field_n */ };
};

Note that instead of void pointers comparison "function" (i.e. the class instance you create) has char * parameters, so you don't bother yourself with type casting.

In C, unfortunately, you can't do this the other way than creating a global variable.

P Shved
  • 96,026
  • 17
  • 121
  • 165