R. Kap
R. Kap

Reputation: 619

How does this passing of an array to "qsort" work?

So I have the main function declared below, to which the user must pass arguments from the command line when first executing the program. Then, it takes the *argv[] array of string inputs and sorts them using the stdlib.h's qsort function, after which it finally prints out all elements, besides the file name, in the input array;

int main(int argc,char *argv[]){                                                                                                                                                                                                
  qsort(argv,args,sizeof(*argv),comp_func);
  for(int U=1;U<argc;U++)printf("%s\n",argv[U]);                                                                                                                                                                                              
}

The comp_func function passed to qsort is shown below:

int comp_func(char*a,char*b){
  return strcmp(*(char **)a,*(char **)b);
}

What I would like to know is what is going on here? I am pretty that qsort sends each 2-length permutation of the array to the given comparator function, both of which are, in this case, strings since argv is an array of strings. However, what I don't get is what is going on here:

strcmp(*(char **)a,*(char **)b)

What is *(char **)a doing? Is it just creating an arbitrary char[] array of a pointer to an arbitrary string with a length of 1, whose first value is then assigned the a, after which it is finally dereferenced, ultimately returning the string a? If so, then why doesn't just plain old a work? Also, interestingly, if I printf just plain old a, it outputs a string of random characters that goes something like ??O_?. However, when I printf *(char **)a instead, I get the actual string input. Why is that? I am a beginner in C, so please bear with me if I ask any more questions.

Upvotes: 1

Views: 604

Answers (3)

LPs
LPs

Reputation: 16243

First of all the compare function should be

int comp_func(const void* a, const void* b)

Then try to analyze the code: you are passing to that function argv that is decalred as char *argv[], that can be seen as char **

So inside the function, you must cast the generic void pointer to the root type char **.

Then you have to dereference to the element of the array of pointers that you want to compare, so: *(char **)

Upvotes: 2

dhke
dhke

Reputation: 15398

qsort() expects a consecutive array of objects as first argument base. Now, argv is an array of const char * pointers, so

qsort(argv, args, sizeof(*argv), comp_func);

says, sort that array of pointers, where sizeof(*argv) is the size of a const char *.

What gets passed to comp_func(), is the address of two objects offset from the base pointer, i.e. the addresses of the char pointers in argv. To get the actual string array/pointer back that contains the argument string, we need to de-reference it. That is, the argument strings are actually at *a and *b.

The signature is still all wrong and should throw compiler warnings all over the place. comp_func() actually takes two const void *:

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

The casts are necessary, since *a is not a valid type with const void * and strcmp() needs const char *, too.

Upvotes: 4

softwarenewbie7331
softwarenewbie7331

Reputation: 967

tldr; its a type-cast followed by a deference.

the typical form of a compare function is

int comp_func(void *a, void *b)

(char**)a casts a into pointer to char*, in this case its actually pointer to the start of the char array.

*(char**)a then dereferences it, meaning the pointer to start of array is passed to the strcmp() function.

printf takes pointer to start of array to print from that pointer onwards until the pointer points to a char '\0' in the array. the gibberish is because it was passed a pointer to pointer, so you get an memory address printed instead.

Upvotes: 2

Related Questions