0

I wanna sort an array of structures (struct Person) by score and it looks like this float PersonScore(Person *record, Person *query) so I can't use qsort, I tried using qsort_r() but it passes for an implicit declaration when I compile. Any ideas?

typedef struct Person_t
{
    char Nom[32];
    char Prenom[32];
    char AdresseEmail[64];
    char Ville[96];
    char Pays[64];
} Person;

static int compare_field(const char *record, const char *query, float *percentage) {
    
    int DLev;
  if (strlen(query) == 0) {
    return 0;                           
  }
  
  DLev = DistanceLevenshtein ( record, query );
  
  *percentage = (1.0f - DLev/((float)(MAX (strlen(record) , strlen(query))))) * 100.0f;
  return 1;
}


float PersonScore(  Person *record,  Person *query) {
     
     float total_match_percentage = 0, temp_percentage;
     int total_match_fields = 0;

  #define COMPAREFIELD(field) if (compare_field(record->field, query->field, &temp_percentage)) ({  total_match_percentage += temp_percentage;  total_match_fields++;   })                  

 COMPAREFIELD (Prenom);
 COMPAREFIELD (Nom);
 COMPAREFIELD (AdresseEmail);
 COMPAREFIELD (Ville);
 COMPAREFIELD (Pays);

  #undef COMPAREFIELD
  return total_match_percentage / (float)total_match_fields;
}

// later in main


  Personne query = {.Prenom = "Jamk", .Ville = "Pondon", .Pays = "United K"};                                                   
        int thunk = 1;
            Personne array[number_of_percentages];
            printf("Before sorting the list is: \n");
             for(int i = 0 ; i < number_of_percentages; i++ ) {
                            printf("%s ", array[i].Prenom);
                        }
    
        qsort_r(array, number_of_percentages, sizeof(*array), compare_scores, &thunk);

            printf("\nAfter sorting the list is: \n");
            for(int i = 0 ; i < number_of_percentages; i++ ) {
      printf("%s", array[i].Prenom);
   }
      
  }
Clifford
  • 88,407
  • 13
  • 85
  • 165
legenw84it
  • 51
  • 7
  • i am not sure why you can't use qsort... with the specific prototype you declared you can't i agree. Why does PersonScore take two Persons, can you describe the function or even better paste its contents? – axelduch Feb 20 '21 at 12:03
  • 1
    Oh sure, I edited the post – legenw84it Feb 20 '21 at 12:12
  • Would it be a problem to just make an array of pairs to link a person to their score, sort that, and then use the indexes to sort the main array? – Jack Lilhammers Feb 20 '21 at 12:32
  • Also, is `PersonScore()` your compare function or you need a compare function to use with qsort()? – Jack Lilhammers Feb 20 '21 at 12:34
  • @JackLilhammers Yes, that's how it should look like, I think. but the compiler is not accepting qsort_r() ... I'll add that part on the post, to give you an idea, under // later in main – legenw84it Feb 20 '21 at 12:44
  • Most likely `qsort_r()` does not exist in your toolchain - it is not a standard function after all. It looks to me that you have over-complicated this and would question the design. – Clifford Feb 20 '21 at 13:22
  • @Clifford I think I might need to just make my own sorting function or maybe create a struct containing record and score.. – legenw84it Feb 20 '21 at 13:34
  • can you pinpoint what you thought overcomplicated matters? – legenw84it Feb 20 '21 at 13:35
  • Well, your struct does' not contain a member "score", You compare function is not a compare function - it should return < 1, 0, or >1 - it only returns 0 or 1. You treat the structure as a string in the "compare function" not as a struct at all. It is completely uninteligable and probably incorrect. Whatever it does, it does not sort structures. Moreover you start by saying. _"an array of structures (struct Person) by score and it looks like this float PersonScore(Person *record, Person *query) "_, which makes no sense at all - that is a function signature not an array or a structure. – Clifford Feb 20 '21 at 17:23
  • ... over complicated in the sense that it would be easier to come up with a solution that _can_ use `qsort()`. Looks like an X-Y problem. The simple answer to your question is that on Windows using Microsoft's C library (As MinGW does), you should use `qsort_s()` (note the different order of compare function arguments though). You should specify the platform and tool chain in the question. I'd hoped you'd get my earlier hint on that. – Clifford Feb 20 '21 at 17:39
  • You have over complicated your question by including code that is hardly relevant to why `qsort_r()` does not exiat and frankly that code is so _unusual_ as to invite further comment that is not really relevant t your question. We probably don't even need to know your reasoning that you cannot use `qsort()` - that's your choice. – Clifford Feb 20 '21 at 17:45
  • @Clifford Yeah, thanks to your advice, I rethought the structure of my code, and kind of worked my way through it from the beginning, I made another struct that contains Person and his Score, and I found a way to make qsort() work, at first, I really tunneled on making qsort_s() work and just ended up making random stuff that doesn't help anything, anyways, here is the link to the code if you wanna check it out, https://onlinegdb.com/Hk_q241fO I think it works just fine, thanks again for the clever remarks, and you can tell me what you feel about this last attempt. – legenw84it Feb 21 '21 at 01:54
  • I'd like to say that I couldn't add Score as an element of the Person struct because it's not required in the project I'm working on, and that threw me off a bit, cus I had to figure out a way to connect Persons to their scores, that's what made everything a little messy, otherwise it should have been pretty straight forward, I think – legenw84it Feb 21 '21 at 02:02

1 Answers1

0

The issue here is that qsort_r() is not a standard function, therefore different implementation of the standard library can have different versions of qsort_r() and you should be aware of that.

For detailed explanations I'm linking these questions:
Different declarations of qsort_r on Mac and Linux
How portable is the re-entrant qsort_r function compared to qsort?

However for your particular issue, if you define _GNU_SOURCE you'll enable GNU extensions and you should be able to compile without the warning.
Here is a good explanation of _GNU_SOURCE
What does "#define _GNU_SOURCE" imply?

To test your code I defined comparePersons()

int comparePersons( const void *person_a, const void *person_b, void *query )
{
    Person *a = (Person *)person_a;
    Person *b = (Person *)person_b;
    Person *q = (Person *)query;

    float a_score = PersonScore(a, q);
    float b_score = PersonScore(b, q);

    if (a_score < b_score)
        return -1;
    else if (a_score > b_score)
        return 1;
    else
        return 0;
}

You can try it here
https://onlinegdb.com/glCpMbGja


Edit

I assumed the OP was working on Linux, because they were using qsort_r() instead of qsort_s().
My example works on onlinegdb.com because they use Linux. On Windows and if you can use C11 the one to use is qsort_s()

For reference:
https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/qsort-s?view=msvc-160
https://en.cppreference.com/w/c/algorithm/qsort

Jack Lilhammers
  • 1,207
  • 7
  • 19
  • I forgot to mention that I already added `#define _GNU_SOURCE` and it didn't work, I work with DevC++ and my compiler is GCC 4.9, I tried again with your code, but the compile failed to recognize what qsort_r(), your code seems to be working well in the site nevertheless – legenw84it Feb 20 '21 at 13:59
  • oh I tried qsort_s() instead of qsort_r() and it compiled just fine – legenw84it Feb 20 '21 at 14:08
  • Ok, so you're on Windows, then yes `qsort_s()` is the right one https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/qsort-s?view=msvc-160 – Jack Lilhammers Feb 20 '21 at 14:20
  • 1
    @BeyondCrisp : Caution - the parameters for the `qsort_s()` compare function are not in the same order as `qsort_r()`. – Clifford Feb 20 '21 at 17:35
  • @Clifford That would have been too easy! :'D – Jack Lilhammers Feb 20 '21 at 18:13