Here is the code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int my_compare(const void * a, const void * b);
int main()
{
char s[][80] =
{ "gxydyv", "gdyvjv", "lfdtvr", "ayfdbk", "sqkpge", "axkoev", "wdjitd", "pyrefu", "mdafyu",
"zdgjjf", "awhlff", "dqupga", "qoprcn", "axjyfb", "hfrgjf", "dvhhhr" };
int i;
puts("#Before:#");
for (i = 0; i < 16; i++)
puts(s[i]);
qsort(s, 16, sizeof *s, my_compare);
putchar('\n');
puts("#After:#");
for (i = 0; i < 16; i++)
puts(s[i]);
return 0;
}
int my_compare(const void *a, const void *b)
{
return strcmp(*(char **)a, *(char **)b);
}
Here is the output:
#Before:#
gxydyv
gdyvjv
lfdtvr
ayfdbk
sqkpge
axkoev
wdjitd
pyrefu
mdafyu
zdgjjf
awhlff
dqupga
qoprcn
axjyfb
hfrgjf
dvhhhr
Segmentation fault
I also notice that the prototype of strcmp is: int strcmp(const char *s1,const char *s2);
I suppose that the type of a and b in my_compare is "pointer to array-of-char". As a result, *(char **)a is a "pointer to char", which is exactly what strcmp expects.
So where is the problem?
Change:
return strcmp(*(char **) a, *(char **) b);
To:
return strcmp(a,b);
You had an extra level of pointer dereferencing that was incorrect and that's why you got the segfault. That is, you were passing the char
values and not the char
pointers [which got masked with the cast].
Note: no need to cast from void *
here.
UPDATE:
In reponse to your question, yes, because of the way you defined s
and the qsort
call.
Your original my_compare
would have been fine if you had done:
char *s[] = { ... };
And changed your qsort
call to:
qsort(s, 16, sizeof(char *), my_compare);
To summarize, here are two ways to do it
int
main()
{
char s[][80] = { ... }
qsort(s, 16, 80, my_compare);
return 0;
}
int
my_compare(const void *a, const void *b)
{
return strcmp(a,b);
}
This is a bit cleaner [uses less space in array]:
int
main()
{
char *s[] = { ... }
qsort(s, 16, sizeof(char *), my_compare);
return 0;
}
int
my_compare(const void *a, const void *b)
{
return strcmp(*(char **) a,*(char **) b);
}
UPDATE #2:
To answer your second question: No
None of these even compile:
return strcmp((char ()[80])a,(char ()[80])b);
return strcmp(*(char ()[80])a,*(char ()[80])b);
return strcmp((char [][80])a,(char [][80])b);
return strcmp(*(char [][80])a,*(char [][80])b);
But, even if the did, they would be logically incorrect. The following does not compile either, but is logically closer to what qsort
is passing:
return strcmp((char [80])a,(char [80])b);
But, when a function passes something defined as char x[80]
it's just the same as char *x
, so qsort
is passing char *
[disguised as void *
].
A side note: Using char *s[]
is far superior. It allows for arbitrary length strings. The other form char s[][80]
will actually fail if a given string exceeds [or is exactly] 80 chars.
I think it's important for you to understand:
The following two are equivalent:
char *
strary(char p[])
{
for (; *p != 0; ++p);
return p;
}
char *
strptr(char *p)
{
for (; *p != 0; ++p);
return p;
}
Consider the following [outer] definitions:
char x[] = { ... };
char *x = ...;
Either of these two may be passed to strary
and/or strptr
in any of the following forms [total of 20]:
strXXX(x);
strXXX(x + 0);
strXXX(&x[0]);
strXXX(x + 1);
strXXX(&x[1]);
Also, see my recent answer here: Issue implementing dynamic array of structures