Thread: Function pointer using qsort

  1. #1
    Registered User
    Join Date
    Nov 2019
    Posts
    135

    Function pointer using qsort

    Here is the description of the exercise:

    https://i.imagesup.co/images2/1b7718...12a633b4e2.png

    Her is my try:

    [C] #include <stdio.h> #include <string.h> #include <stdlib.h> int compareStrin - Pastebin.com

    But for some reason I have a problem with the call to qsort function...
    Something wrong with the passing of *string - I don't understand what exactly the problem is and how to fix it.

    Does some one know?
    Thanks!

  2. #2
    Registered User
    Join Date
    Dec 2017
    Posts
    1,632
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
     
    int compareStrings(const void *s1, const void *s2) {
        return strcmp(*(char**)s1, *(char**)s2);
    }
     
    void stringSort(char** strings, size_t len) {
        qsort(strings, len, sizeof *strings, compareStrings);
    }
      
    int main() {
        char *arr[] = {"C", "CCC", "ABC", "test", "a", "c++"};
        int n = sizeof(arr) / sizeof(arr[0]);
      
        stringSort(arr, n);
      
        for (int i = 0; i < n; i++)
            printf("%s ", arr[i]);
        putchar('\n');
     
        return 0;
    }
    A little inaccuracy saves tons of explanation. - H.H. Munro

  3. #3
    Registered User
    Join Date
    Nov 2019
    Posts
    135
    Quote Originally Posted by john.c View Post
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
     
    int compareStrings(const void *s1, const void *s2) {
        return strcmp(*(char**)s1, *(char**)s2);
    }
     
    void stringSort(char** strings, size_t len) {
        qsort(strings, len, sizeof *strings, compareStrings);
    }
      
    int main() {
        char *arr[] = {"C", "CCC", "ABC", "test", "a", "c++"};
        int n = sizeof(arr) / sizeof(arr[0]);
      
        stringSort(arr, n);
      
        for (int i = 0; i < n; i++)
            printf("%s ", arr[i]);
        putchar('\n');
     
        return 0;
    }
    Amazing, thank you!!

    Can you explain briefly my misunderstanding of using pointers?

    You pass to qsort's first argument pointer to char pointer named strings.
    I understand why it's correct and I was wrong - I had to pass the pointer to the first element in the array, which is exactly strings.

    As for compareStrings function - I didn't succeed to understand unfortunately.
    We are passing two pointers, which are elements of the pointer to pointer array (strings). So why we are casting it to char**? And again de-referencing it?...
    I'm a little mixed up really.


    Thank you.

  4. #4
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    It might be easier to first consider an int comparison function for qsort to sort ints:
    Code:
    int compareInts(const void *s1, const void *s2) {
        int x = *(int*)s1;
        int y = *(int*)s2;
        return (x < y) ? -1 : (x > y);
    }
    Now think of it from the perspective of qsort: qsort needs to call this function to compare two ints. When it does so, it would be passing a pointer to each int, which it really only "knows" as a sequence of sizeof(int) bytes, as the respective argument. These arguments correspond to the s1 and s2 parameters of compareInts, which are const void* because qsort only deals with the byte sequences of specific size rather than the types from the caller. So, you need to cast the const void* to int* (or for const-correctness, to const int*, but that doesn't matter here) such that you're reinterpreting the sizeof(int) sequence of bytes as an int (which is after all what it is). But now that you have a pointer to int, you want to compare the int values themselves, which is why you dereference the result to obtain the int.

    Now, going back to your compareStrings function, you're basically replacing int with char*, and calling strcmp instead of implementing the value comparison yourself. That's why there's the cast to char** and the dereference for each argument.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  5. #5
    Registered User
    Join Date
    Dec 2017
    Posts
    1,632
    You can't dereference a void pointer since it has no type information (such as the size of the object pointed to). So you need to cast it to what it really is, and then dereference it. qsort passes a pointer to the element. The elements are char*. So qsort is passing a char**. Dereferencing that yields a pointer to the string.
    A little inaccuracy saves tons of explanation. - H.H. Munro

  6. #6
    Registered User
    Join Date
    Nov 2019
    Posts
    135
    Quote Originally Posted by laserlight View Post
    It might be easier to first consider an int comparison function for qsort to sort ints:
    Code:
    int compareInts(const void *s1, const void *s2) {
        int x = *(int*)s1;
        int y = *(int*)s2;
        return (x < y) ? -1 : (x > y);
    }
    Now think of it from the perspective of qsort: qsort needs to call this function to compare two ints. When it does so, it would be passing a pointer to each int, which it really only "knows" as a sequence of sizeof(int) bytes, as the respective argument. These arguments correspond to the s1 and s2 parameters of compareInts, which are const void* because qsort only deals with the byte sequences of specific size rather than the types from the caller. So, you need to cast the const void* to int* (or for const-correctness, to const int*, but that doesn't matter here) such that you're reinterpreting the sizeof(int) sequence of bytes as an int (which is after all what it is). But now that you have a pointer to int, you want to compare the int values themselves, which is why you dereference the result to obtain the int.

    Now, going back to your compareStrings function, you're basically replacing int with char*, and calling strcmp instead of implementing the value comparison yourself. That's why there's the cast to char** and the dereference for each argument.
    I understood all your good explanation except for one thing: "That's why there's the cast to char**".
    I didn't understand exactly why casting to char** and not char*?

    Thanks.

  7. #7
    Registered User
    Join Date
    Dec 2017
    Posts
    1,632
    As I said in my previous post, you need to cast the void* to the exact pointer type that qsort passed in. qsort passes a pointer to an array element. Since the elements are already char*, qsort passes a char**.
    A little inaccuracy saves tons of explanation. - H.H. Munro

  8. #8
    Registered User
    Join Date
    Nov 2019
    Posts
    135
    Quote Originally Posted by john.c View Post
    As I said in my previous post, you need to cast the void* to the exact pointer type that qsort passed in. qsort passes a pointer to an array element. Since the elements are already char*, qsort passes a char**.
    Got it - thanks!

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. qsort() and pointer problem
    By implor in forum C Programming
    Replies: 26
    Last Post: 06-09-2009, 06:18 PM
  2. qsort() in Array of Pointer to String
    By vb.bajpai in forum C Programming
    Replies: 8
    Last Post: 06-16-2007, 04:18 PM
  3. qsort() w/ pointer swapping
    By soopah256 in forum C Programming
    Replies: 10
    Last Post: 12-05-2003, 07:54 AM
  4. qsort using function ptr
    By nomes in forum C Programming
    Replies: 5
    Last Post: 10-01-2002, 04:41 PM
  5. help with qsort() function.
    By Unregistered in forum C++ Programming
    Replies: 11
    Last Post: 03-03-2002, 10:39 AM

Tags for this Thread