I am just starting to learn C. Any help is appreciated!
I have an array of pointers to a struct, and I want to use the built-in qsort function to sort the array according to values in the structs the pointers point to. I am trying to use a compare function as demonstrated in the official docs.
The following version fails:
int compare_nodes(const void* a, const void* b){
const struct ListNode * ptr1 = ((const struct ListNode *) a);
const struct ListNode * ptr2 = ((const struct ListNode *) b);
// const struct ListNode * ptr1 = *((const struct ListNode **) a);
// const struct ListNode * ptr2 = *((const struct ListNode **) b);
int arg1 = ptr1 -> val;
int arg2 = ptr2 -> val;
if(arg1 < arg2) return -1;
if(arg1 > arg2) return 1;
return 0;
}
This version succeeds:
int compare_nodes(const void* a, const void* b){
// const struct ListNode * ptr1 = ((const struct ListNode *) a);
// const struct ListNode * ptr2 = ((const struct ListNode *) b);
const struct ListNode * ptr1 = *((const struct ListNode **) a);
const struct ListNode * ptr2 = *((const struct ListNode **) b);
int arg1 = ptr1 -> val;
int arg2 = ptr2 -> val;
if(arg1 < arg2) return -1;
if(arg1 > arg2) return 1;
return 0;
}
I do not understand the difference between the two versions:
- If casting only tells the compiler how to interpret the address the pointer points to, what is the problem in version 1? Is it not enough to tell the compiler to interpret the pointer to void as a pointer to struct ListNode? Why do I need to add a layer of indirection with casting, just to then remove one layer with dereferencing?
- Does C's pass-by-value play any role here? I could not think of any reason why by myself.
I found the following resources about this question. Although they seemed to explain this problem (especially resource 6), I did not understand them:
Here's the full code:
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
struct ListNode {
int val;
struct ListNode *next;
};
int calc_list_length(struct ListNode * head){
int target = 0;
struct ListNode * tmp = head;
while (tmp)
{
target++;
tmp = tmp -> next;
}
return target;
}
int compare_nodes(const void* a, const void* b){
// const struct ListNode * ptr1 = ((const struct ListNode *) a);
// const struct ListNode * ptr2 = ((const struct ListNode *) b);
const struct ListNode * ptr1 = *((const struct ListNode **) a);
const struct ListNode * ptr2 = *((const struct ListNode **) b);
int arg1 = ptr1 -> val;
int arg2 = ptr2 -> val;
if(arg1 < arg2) return -1;
if(arg1 > arg2) return 1;
return 0;
}
struct ListNode* sortList(struct ListNode* head){
if(!head) return NULL;
int list_length = calc_list_length(head);
struct ListNode * tmp = head;
struct ListNode * arr[list_length];
for (int i = 0; i < list_length; i++)
{
arr[i] = tmp;
tmp = tmp -> next;
}
for (int i = 0; i < list_length; i++) {
printf("%d ", arr[i] -> val);
}
printf("\n");
qsort(arr, list_length, sizeof(struct ListNode *), compare_nodes);
for (int i = 0; i < list_length; i++) {
printf("%d ", arr[i] -> val);
}
printf("\n");
}
int main(){
// [2,1,4,3]
struct ListNode node4 = {.val = 3, . next = NULL};
struct ListNode * ptr4 = &node4;
struct ListNode node3 = {.val = 4, .next = ptr4};
struct ListNode * ptr3 = &node3;
struct ListNode node2 = {.val = 1, .next = ptr3};
struct ListNode * ptr2 = &node2;
struct ListNode node1 = {.val = 2, .next = ptr2};
struct ListNode * ptr1 = &node1;
sortList(ptr1);
getchar();
return 0;
}
Thanks in advance. I hope you point me in the right direction.