user191776
user191776

Reputation:

Use of pointer to const

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

Answers (4)

alesplin
alesplin

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

aschepler
aschepler

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 chars. 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

Gintautas Miliauskas
Gintautas Miliauskas

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

Steve Townsend
Steve Townsend

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

Related Questions