Difficulty: Medium
Correct Answer: int cmp(const void *a, const void *b) { const struct student *sa = a; const struct student *sb = b; if (sa->marks < sb->marks) return -1; if (sa->marks > sb->marks) return 1; return 0; } qsort(arr, N, sizeof(struct student), cmp);
Explanation:
Introduction / Context:
The qsort function in C is a generic sorting routine that can sort arrays of any element type as long as the programmer supplies the correct element size and a comparison function. Sorting arrays of structures is a common task, for example when ordering student records by marks. This question checks whether you understand the required function signature for the comparator and how to pass it correctly to qsort when working with a struct student array.
Given Data / Assumptions:
Concept / Approach:
The prototype of qsort is void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));. The comparator must accept two pointers to elements, typed as const void *, and return a negative value if the first element is less than the second, zero if equal and positive if greater. Inside the comparator, you cast the void pointers to pointers to struct student and compare the marks fields. The qsort call passes the base address arr, the count N, the element size sizeof(struct student) and the comparator function pointer cmp.
Step-by-Step Solution:
Step 1: Define a comparator with the exact signature required: int cmp(const void *a, const void *b).
Step 2: Inside cmp, cast a and b to const struct student * and store them in variables sa and sb.
Step 3: Compare sa->marks and sb->marks. Return -1 if sa->marks is less, 1 if greater and 0 if equal, to indicate sorting order.
Step 4: Call qsort with base pointer arr, count N, element size sizeof(struct student) and comparator cmp.
Step 5: After qsort returns, arr will be sorted in ascending order of marks as defined by cmp.
Verification / Alternative check:
The comparator signature must match qsort's expectations. If you try to pass a function taking struct student parameters directly, the compiler will complain because the pointer to function types are incompatible. Likewise, swapping nmemb and size arguments in qsort leads to undefined behaviour because qsort uses size to stride through the array. Testing the correct code with sample data shows that the array is ordered by increasing marks, confirming the implementation.
Why Other Options Are Wrong:
Option B uses a comparator that takes struct student by value, which does not match the required int (*)(const void *, const void *) signature and cannot be passed to qsort without a cast that would break type safety. Option C uses the right comparison logic but swaps the nmemb and size arguments in qsort, which is incorrect. Option D omits the comparator entirely, even though qsort cannot sort arbitrary structs without a comparison function that understands their contents.
Common Pitfalls:
A frequent mistake is to forget const qualifiers or to cast void * incorrectly, leading to undefined behaviour. Another pitfall is to return a simple subtraction such as sa->marks - sb->marks when marks is a signed type that could overflow; although often acceptable in small ranges, the safer approach is to use explicit comparisons as in the solution. Finally, developers sometimes swap the nmemb and size arguments, which compiles but produces incorrect memory accesses at run time.
Final Answer:
You must write a comparator int cmp(const void *a, const void *b) that casts to const struct student * and compares marks, then call qsort(arr, N, sizeof(struct student), cmp); to sort the array by marks.
Discussion & Comments