Home > database >  Is there a C function which, given a struct array with different data types, can sort the array with
Is there a C function which, given a struct array with different data types, can sort the array with

Time:10-20

I am sorting/searching a struct array.

struct Substance
{
   char name[NAME_SIZE]
   int mass;
   double halftime;
}

The sorting/searching is done after prompting the user to choose what member of the struct to sort by, i.e by name, mass or halftime.

Is there a way to make a general function that can work with all of the three data types or do I have to write different functions for each?

The reason why I don't want to write several functions is that 90% of the code in each function would be the same.

I am especially struggling with the fact that I have to get the member I want to operate on for each iteration, i.e substances[i].mass to access the mass and this syntax obviously has to be different for each member of the struct.

I tried to do some pre processing to avoid this issue:

switch(choice)
{
   case '1':
      memcpy(current, substances[i].name, NAME_SIZE);
      break;
   case '2':
      sprintf(current, "%d", substances[i].mass);
      break;
   case '3':
      sprintf(current, "%lf", substances[i].halftime);
}

But if I want to sort by mass I would then have to convert every other substance's mass in the struct array aswell.

I have also thought about representing every member as the same data type in the first place and then just convert in when needed, like printing, writing to file etc but I don't know what data type I would use.

A general use case would be:

/*
Do you want to sort by (1) name, (2) mass or (3) halftime: 2

Sorted list by mass:
Name      Mass     Halftime
Zirconium 91       ...
Radon     220      ...
Radon     222      ...
Uranium   238      ...
*/

CodePudding user response:

Yes qsort(). example:

Given struct:

struct Substance
{
   char name[NAME_SIZE]
   int mass;
   double halftime;
};

And assuming array defined substances[N];//has been populated, then examples of calls can be:

qsort(substances, N, sizeof (struct Substance), compareName);
qsort(substances, N, sizeof (struct Substance), compareMass);
qsort(substances, N, sizeof (struct Substance), compareHtime);

...with the forms for your compare functions being passed in qsort() being:

int compareName(const void *a, const void *b)
{
    const struct Substance *ia = a;
    const struct Substance *ib = b;
    return strcmp(ia->name, ib->name);//returns -1, 0 1 per strcmp rules
}

int compareMass(const void *a, const void *b)
{
    const struct Substance *ia = a;
    const struct Substance *ib = b;
    return ia->mass == ib->mass ? 0 : 
                                  ia->mass > ib->mass ? 1 : -1;
}

int compareHtime(const void *a, const void *b)
{
    const struct Substance *ia = a;
    const struct Substance *ib = b;
    return fabs(ia->halftime - ib->halftime) < 0.00001 ? 0 :
                                (ia->halftime - ib->halftime) > 1 ? 1 : -1;
}

"Is there a way to make a general function that can work with all of the three data types or do I have to write different functions for each?"

You could create a void function that uses your switch(), and uses an enum. to decide which of the three compare functions to call. Eg:

enum {
    NAME,
    MASS,
    HALF,
    TYPE_MAX
};

void sort(struct Substance *s, size_t size, int type)
{
    switch(type)
        case NAME;
            qsort(s, size, sizeof (struct Substance), compareName);
            break;
        case 
              ...
              
  • Related