Thread: Qsort an array of chars nested in a struct

  1. #1
    Registered User
    Join Date
    Mar 2017
    Posts
    7

    Qsort an array of chars nested in a struct

    Hello,

    I've searched through many code examples and think that I have the correct compare function, but my problem is that when I run the code, I get an error EXC_BAD_ACCESS. XCode points to the cmpfunc function as the culprit. I know I have allocated memory to all my elements, as I can print the array before it gets passed to qsort. Could someone point me in the right direction for where I am having issues? Please and thank you very much!

    Below are my structs so you can see how many levels down I am when I am qsorting:
    Code:
    typedef struct {
        unsigned int siteId;
        unsigned int tableTypeId;    
        unsigned int surMatId;
        unsigned int strucMatId;
        char *streetAve;
        unsigned int neighbourhoodId;
        char *neighbourhoodName;
        unsigned int ward;
        char *latitude;
        char *longitude;
    } Entries;
    
    typedef struct {
        int size;
        Entries **entry;
    } PicnicTable;
    
    typedef struct {
        Table *tableTypeTable;
        Table *surfaceMaterialTable;
        Table *structuralMaterialTable;
        NeighbourHoodTable *neighborhoodTable;
        PicnicTable *picnicTableTable;
    } DataBase;
    
    extern DataBase *DB;
    Code:
    int cmpfunc(const void *a, const void *b) {
         return strcmp((*(Entries**)a)->neighbourhoodName, (*(Entries**)b)->neighbourhoodName);
    }
    
    //    just ignore the below, I was experimenting
    //    Entries left = *(Entries*)a;
    //    Entries right = *(Entries*)b;
    //    return (*(int*)left.neighbourhoodName - *(int*)right.neighbourhoodName);
    
    //    return (*(int*)(*(Entries**)a)->neighbourhoodName - *(int*)(*(Entries**)b)->neighbourhoodName);
        
    //    Entries *left = *(Entries**)a;
    //    Entries *right = *(Entries**)b;
    //    return (*(int*)left->neighbourhoodName - *(int*)right->neighbourhoodName);
    Code:
    Entries **ent = DB->picnicTableTable->entry;
    qsort(ent,DB->picnicTableTable->size-1, sizeof(Entries*), cmpfunc);

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    37,600
    It looks like you have too much dereferencing going on.

    > qsort(ent,DB->picnicTableTable->size-1, sizeof(Entries*), cmpfunc);
    The type you want to cast to in the cmpfunc is Entries**

    If you're sorting an array of T, then the cmp function gets two T* pointers (as const void*).

    So do this, and stop trying to compress everything into a single line.
    Code:
    int cmpfunc(const void *a, const void *b) {
        Entries **pa = (Entries**)a;
        Entries **pb = (Entries**)b;
        return strcmp(pa->neighbourhoodName, pb->neighbourhoodName);
    }
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User
    Join Date
    Mar 2017
    Posts
    7
    Thank you for the suggestion, though casting it as you pointed out doesn't allow me access to the members of the struct. I would have to cast it like:
    Code:
    Entries *pa = (Entries*)a;
    Either way, I still get the same access error.

  4. #4
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    37,600
    How about this?
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    typedef struct {
        unsigned int siteId;
        unsigned int tableTypeId;    
        unsigned int surMatId;
        unsigned int strucMatId;
        char *streetAve;
        unsigned int neighbourhoodId;
        char *neighbourhoodName;
        unsigned int ward;
        char *latitude;
        char *longitude;
    } Entries;
    
    int cmpfunc(const void *a, const void *b) {
        Entries **pa = (Entries**)a;
        Entries **pb = (Entries**)b;
        return strcmp((*pa)->neighbourhoodName, (*pb)->neighbourhoodName);
    }
    
    int main( ) {
      Entries test[2] = {
        { .neighbourhoodName = "world" },
        { .neighbourhoodName = "hello" },
      };
      Entries *t[2] = {
        &test[0],
        &test[1]
      };
      Entries **ent = t;
      qsort(ent,2, sizeof(Entries*), cmpfunc);
      printf("%s %s\n", t[0]->neighbourhoodName, t[1]->neighbourhoodName);
      return 0;
    }
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  5. #5
    Registered User
    Join Date
    Mar 2017
    Posts
    7
    That definitely runs with my code, I forgot to put brackets around pa and pb before. Geez

    It doesn't fix my bad_access error, which makes me think that my real problem is how I'm allocating/accessing memory. I'm pretty sure the memory malloc'd before qsort isn't affected in terms of how much needs to be allocated? Weirdness. I think the dereferencing dance has me spinning in circles.

    Either way, thank you for narrowing down my scope of tests! :-)

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Use qsort() to sort array of pointers to struct
    By VIgnotam in forum C Programming
    Replies: 4
    Last Post: 04-04-2012, 06:42 PM
  2. Replies: 3
    Last Post: 03-03-2010, 03:35 PM
  3. seg fault with nested struct from pointer
    By seaking1 in forum C Programming
    Replies: 4
    Last Post: 05-01-2009, 03:09 PM
  4. Help with nested struct pointers
    By vampireiam in forum C Programming
    Replies: 10
    Last Post: 11-13-2007, 11:59 AM
  5. nested struct , fread ,fwrite
    By magicz69 in forum C Programming
    Replies: 4
    Last Post: 08-01-2004, 09:47 AM

Tags for this Thread