1

I tried to sort an array of strings with qsort but got this warning:

warning: passing argument 4 of 'qsort' from incompatible pointer type

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#define MAX_PRODUCTS   1000

int main (void) {
    int i, index = 0, isUnique;
    char products[MAX_PRODUCTS][100];
    char product[100];
    int  count[MAX_PRODUCTS];

    FILE * fp;

    fp = fopen ("one.txt", "r");

    // Read words from file and put in array if unique
    while (fscanf(fp, "%s", product) != EOF){
        isUnique = 1;
        for (i=0; i<index && isUnique; i++){
            if (strcmp(products[i], product) == 0){
                isUnique = 0;
            }   
        }

        if (isUnique) {
            strcpy(products[index], product);
            index++;
        }

        else {
            count[i - 1]++;
        }
    }

    qsort(products, MAX_PRODUCTS, sizeof(char*), strcmp);

    fclose(fp);

    return 0;
}

I also tried a custom function to compare strings but this didn't worked either. What can I do to fix it?

2
  • 1
    Please show your custom function Commented Jan 22, 2020 at 7:37
  • Besides the warning you have another problem: You tell your compiler you have an array of char * while you have an array of char[100] Commented Jan 22, 2020 at 7:38

3 Answers 3

2

qsort is documented on the Microsoft website where it states:

compare Pointer to a user-supplied routine that compares two array elements and returns a value that specifies their relationship.


Use this:

int compare (const void * a, const void * b)
{
  return strcmp((char*)a, (char*)b );
}

the following way:

qsort(products, MAX_PRODUCTS, 100, compare);
Sign up to request clarification or add additional context in comments.

9 Comments

Looks like the reason for the downvote stays unrevealed, just as the reason for using this function does. A good answer should explain why and how to "Use this:", not just throw a fish.
@Tommylee2k Nevertheless, it is the only conform way to remedy the warning, that is posted for this issue. Hence, albeit a big terse, I do not see that a downvote is reasonable.
@AndrewTruckle thank you for the corrections of the answer! =)
@AndrewTruckle i'm not going to argue. answering the question that has 80 lines of code and 2 lines of text explaining the problem with 3 lines of code and 1 line of text sounds reasonable to me. Had the OP longer explanation of his/her problems or had OP asked about the details later, I'd be glad to elaborate...
Downvote because this answer does not make it clear what the problem is. Ie it needs to say that OP was sorting char arrays but gave qsort an argument that implied they were sorting char pointers. As it stands this the answer requires a reader to debug OP's code themselves and so is useless as search result on this site.
|
1

You tell qsort(), that you want to sort an array of pointers, but have indeed an array of arrays!

This gives you an array of pointers:

char *products[MAX_PRODUCTS]

for (int i = 0; i < sizeof(products)/sizeof(*products); i++) {
    products[i] = malloc(100);
}

You could also sort the whole array members, but this involves swapping the whole strings (strictly spoken, the whole arrays, even if the strings are shorter) a multitude of times, which can be quite inefficient. It is much faster to only swap the pointers.

Furthermore, the signature of strcmp() does not match the prototype, that qsort expects. So you should wrap it in a compare-function with prototype

int compar(const void *, const void *);

as shown in the manpage. Then, the compiler should not complain any more.

Comments

1

You actually have more problems than the warning you get:

  • You always sort MAX_PRODUCTS elements of the products array, no matter how many elements are actually valid (you sort uninitialized and indeterminate strings).

  • You say that the element-size of the products array is sizeof(char*), but products is an array of arrays, so each element of products is sizeof producst[0] large.


Now for the warning itself: The declaration of strcmp is

int strcmp( const char *lhs, const char *rhs );

while the comparison function passed to qsort is

int (*comp)(const void *, const void *)

The argument types are different. A seemingly possible solution is to cast the strcmp pointer to the correct type:

typedef int (*sortfun_type)(const void *, const void *);

// After the loop the variable index should be the number of strings read
qsort(products, index, sizeof products[0], (sortfun_type) &strcmp);

As noted in a comment, this is technically not correct (but should work anyway). The proper solution is to write a wrapper-function with the correct arguments types, which then calls strcmp (as shown by others).

1 Comment

If you see it strictly, this invokes UB: "A pointer is used to call a function whose type is not compatible with the pointed-to type". The clean way is to write a wrapper function, as shown in the answer of @lenik . Having said that, it will probably work anyway.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.