1

So I have a struct that I want to sort by each element, ascending and descending.

I'm creating 14 different sort function because I don't know how to pass struct element as a function argument.

I want to cut it to 2 sort function ascending & descending, so I don't have 14 functions.

How do I deal with this?? Thanks in advance!

struct propertySales{
    unsigned int tanggal[3];
    char pelanggan[30];
    char jenisProperty[30];
    char namaProperty[30];
    int jumlahProperty;
    double hargaProperty;
    double totalPembayaran;
}Arr[100], compare[100], temp;

void sort_totalPembayaran_descending(){
    int currentIndex=index_counter();
    for(int i=0; i<(currentIndex-1); i++){
        for (int j=0; j<(currentIndex-i-1); j++){
            if (compare[j].totalPembayaran < compare[j+1].totalPembayaran){
                swap(&compare[j], &compare[j+1]);
            }
        }
    }
    system("cls");
    printf("Sorting berdasarkan total pembayaran (Descending)\n");
    print_column();
    print_data(compare);
}
Ken White
  • 123,280
  • 14
  • 225
  • 444
  • You only need a proper comparison function for qsort() for each of the sorts you wish to do. – Dúthomhas Jan 10 '23 at 00:44
  • This is a shortcoming in `qsort`. You can write your own sort routine that takes an additional parameter, of type `const void *`, that it relays to the comparison routine. And your comparison routines would also take such a parameter. For that parameter, you would define a type, often a structure type, that tells the comparison routine what and how to compare. It could have an enumeration saying which member to compare and a Boolean indicating whether to compare for ascending or descending. [Relevant.](https://stackoverflow.com/questions/4210689/pass-extra-parameter-to-comparator-for-qsort) – Eric Postpischil Jan 10 '23 at 00:54
  • Do you really want to sort the array elements "permanently"? Or, do you want to have access to those elements in a sorted sequence (eg: for one time printing)? – Fe2O3 Jan 10 '23 at 00:55
  • See, amongst others, [Need help using `qsort()` with an array of structs](https://stackoverflow.com/q/6105513/15168), [Using `qsort()` to sort pointers to structs containing strings](https://stackoverflow.com/q/10443132/15168), and [Writing a compare function for a structure for `qsort()`?](https://stackoverflow.com/q/53465147/15168) – Jonathan Leffler Jan 10 '23 at 00:56
  • The standard does specify a `qsort_s` function with this feature, but it is optional. – Eric Postpischil Jan 10 '23 at 00:56
  • A reduction in your code would be as simple as always sorting in ascending sequence, then accessing either first-to-last or last-to-first when you need the elements in ascending or descending sequence... – Fe2O3 Jan 10 '23 at 01:04
  • Unless you use `qsort_r()` (on Unix-like systems, but the variant on Linux is different from the variant on macOS/BSD — beware) or `qsort_s()` (optional in C11 and not widely implemented), or use a global variable (can you say "Yuck!"?), you can't configure the comparator at runtime. So, you will likely end up with 14 functions, one for each comparison style. You can write the 'sort descending' comparator in terms of the 'sort ascending' one: `int xyx_cmp_desc(const void *v1, const *v2) { return -xyx_cmp_asc(v1, v2); }` (but it can't be inlined; you need to pass a pointer to `qsort()`). – Jonathan Leffler Jan 10 '23 at 01:04
  • Style Guide: do not mix sorting and printing in a function. Separate the sorting from the printing — two functions minimum. Each of those can be used in other contexts, whereas the combined function is very limiting. And things like `system("cls");` are definitely counter-productive for general-purpose code. (If need be, you can create a `sort_and_print()` function, but it should call other functions to sort and print. You already have your printing somewhat separated. – Jonathan Leffler Jan 10 '23 at 01:07
  • @Fe2O3 I want to sort for one time printing – Raynaldy Dwi Jan 10 '23 at 01:08
  • Thanks for all the help guys, I will try your suggestion! – Raynaldy Dwi Jan 10 '23 at 01:09
  • "_I want to sort for one time printing_" There will be a point at which it might make sense to allocate and fill an array of pointers to each element, and then sort the array of pointers (based on the data in each element that each pointer points at). Shifting around larger chunks of data (as compared to pointer values) comes with a cost. – Fe2O3 Jan 10 '23 at 01:14

1 Answers1

1

If you wish to sort by the totalPembayaran field, then you want to create a comparison function which takes two void pointers to propertySales structs.

int compare_totalPembayaran_asc(const void *a, const void *b) {
    struct propertySales *c = (struct propertySales *)a;
    struct propertySales *d = (struct propertySales *)b;

    if (c->totalPembayaran < d->totalPembayaran)
        return -1;
    else if (c->totalPembayaran > d->totalPembayaran)
        return 1;
    else 
        return 0;
}

Now you can provide this to qsort to sort your array in ascending order.

qsort(arr, 100, sizeof(propertySales), compare_totalPembayaran_asc);

Comparing in descending order just requires writing another comparison function and changing the values returned.

int compare_totalPembayaran_desc(const void *a, const void *b) {
    struct propertySales *c = (struct propertySales *)a;
    struct propertySales *d = (struct propertySales *)b;

    if (c->totalPembayaran < d->totalPembayaran)
        return ...;
    else if (c->totalPembayaran > d->totalPembayaran)
        return ...;
    else 
        return 0;
}
Chris
  • 26,361
  • 5
  • 21
  • 42
  • 1
    You can also use `int xyz_desc(const void *a, const void *b) { return -xyz_asc(a, b); }` for the descending sort — which reduces the risk of getting the ascending and descending comparators out of sync with each other. – Jonathan Leffler Jan 10 '23 at 00:57