Reputation:
From the man page of qsort, in an example of sorting strings:
static int
cmpstringp(const void *p1, const void *p2)
{
/* The actual arguments to this function are "pointers to
pointers to char", but strcmp(3) arguments are "pointers
to char", hence the following cast plus dereference */
return strcmp(* (char * const *) p1, * (char * const *) p2);
}
Why is it necessary to have char * const *
in the arguments to strcmp()
? Isn't char *
enough?
Upvotes: 0
Views: 312
Reputation: 1322
A comparison function passed to qsort has no business modifying the items it's comparing.
This is why the general case of qsort looks like:
void qsort(void *base, size_t nmemb, size_t size, int(*compar)(const void *, const void *));
Upvotes: 0
Reputation: 72271
const void* p1
says that whatever p1
points at is not changed by this function. If you did
char** p1_copy = (char**) p1;
that would be a setup to potentially break that promise, because you could then do
*p1_copy = "Something else";
So a cast from const void*
to char**
is said to "cast away const". Legal, but some compilers will warn if you use a cast to both cast away const and otherwise change the type at once.
The cast that doesn't break the promise of the const void* p1
declaration is the one used:
char* const* p1_arg = (char* const*) p1;
Now *p1_arg
, the thing p1
points to, can't be changed just like we said. You could change the characters in it though:
*p1_arg[0] = 'x';
The function declaration never said anything about them, and you say you know them to originally be non-const char
s. So it's allowable, even though the function doesn't actually do any such thing.
Then you dereference that (as an rvalue) to get a char*
. That can legally be passed as the const char*
argument to strcmp
by automatic const
promotion.
Upvotes: 2
Reputation: 7892
Technically, if you wanted to get rid of the consts, the cast would be to char **
, not char *
. The const
is left in the cast because the arguments to cmpstringp
are also const
.
Upvotes: 1
Reputation: 54128
strcmp
is declared as
int strcmp(
const char *string1,
const char *string2
);
This properly expresses the function's interface contract - which is that strcmp
will not modify its input data - and allows the compiler to optimize inside the function (assuming it were not part of the CRT, and likely in assembler already).
Upvotes: 3