FAQ 13.8, comparing strings

V

vippstar

Either you are not understanding me or I am not able to understand this
<p_strcmp> thing. This is your code:

compare these 2 paragraphs:

In theory, you get a <pointer to const void> and you use it to initialize
a <pointer to a const pointer to char> . In practice, you get a <pointer
to a pointer to char> and you are using it to initialize a <pointer to a
const pointer to char> and then dereference it to a <const pointer to
char>.

Because you already know that the input argument will be <char**> so we
/You/ do know that. The compiler doesn't. In your code you dereference
a void * pointer and then use its value, which is not possible in ISO
C.
can simply dereference it and get a <char*> which could be used for
How do you get a char * if you dereference a void *?
<strcmp> since <strcmp> does not require a <const pointer>. Hence It
could be simply this:

int p_strcmp(const void *pv1, const void *pv2)
{
return strcmp(*pv1, *pv2);
Here, you dereference a void pointer as I said before. This void *
pointer is given the value of a char ** pointer. That's why RH assigns
it to such pointer, and then dereferences it. Consider this:

#include <stdio.h>
int f(void *p);
int main(void) {
int i = 10;
int *k = &i;
printf("%d\n", f(&k)); // pass address of int *, type is int **
return 0;
}
int f(void *p) {
int **i = p; // p points to an int **
return **i + 10;
}

It's the same thing.

P.S. Your signature appeared twice.
 
S

santosh

arnuld wrote:

Now I got it. <void*> is a compile-time phenomenon which , actually,
helps a lot as run-time phenomenon because in many cases we could
know the types only at run-time.

<snip>

Can you clarify this? What do you mean by "compile-time phenomenon"
and "run-time phenomenon"?
 
A

arnuld

#include <string.h>
int p_strcmp(const void *pv1, const void *pv2)
{
char * const * v1 = pv1;
char * const * v2 = pv2;
return strcmp(*v1, *v2);
}


Either you are not understanding me or I am not able to understand this
<p_strcmp> thing. This is your code:



compare these 2 paragraphs:

In theory, you get a <pointer to const void> and you use it to initialize
a <pointer to a const pointer to char> . In practice, you get a <pointer
to a pointer to char> and you are using it to initialize a <pointer to a
const pointer to char> and then dereference it to a <const pointer to
char>.


Because you already know that the input argument will be <char**> so we
can simply dereference it and get a <char*> which could be used for
<strcmp> since <strcmp> does not require a <const pointer>. Hence It
could be simply this:


int p_strcmp(const void *pv1, const void *pv2)
{
return strcmp(*pv1, *pv2);
}


I need explanation on this as it<p_strcmp> code is biting me
from the very 1st day I saw it in section 13.8 of the FAQ and I still
can't seem to comprehend the WHY of it.
 
A

arnuld

#include <stdio.h>
int f(void *p);
int main(void) {
int i = 10;
int *k = &i;
printf("%d\n", f(&k)); // pass address of int *, type is int **
return 0;
}
int f(void *p) {
int **i = p; // p points to an int **
return **i + 10;
}

It's the same thing.

O...K..A..Y....

Now I got it. <void*> is a compile-time phenomenon which , actually,
helps a lot as run-time phenomenon because in many cases we could know
the types only at run-time.


Right ?


still one questions remains:


#include <string.h>
int p_strcmp(const void *pv1, const void *pv2)
{
char * const * v1 = pv1;
char * const * v2 = pv2;
return strcmp(*v1, *v2);
}


I can use <char** v1 = pv1> or <const char** v1 = pv1>

why use <char *const *v1 = pv1> ?
 
P

Peter Nilsson

santosh said:
<snip>

Can you clarify this? What do you mean by "compile-time
phenomenon" and "run-time phenomenon"?

Sounds like the OP is drawing the distinction between object
type, which is known at compile time since C is statically
typed, and an object's effective type which need only be
known at runtime.
 
U

Ulrich Eckhardt

arnuld said:
int p_strcmp(const void *pv1, const void *pv2)
{
char * const * v1 = pv1;
char * const * v2 = pv2;
return strcmp(*v1, *v2);
}


I can use <char** v1 = pv1> or <const char** v1 = pv1>

why use <char *const *v1 = pv1> ?

The const or volatile qualifier applies to the left, with the exception of
when it is at the leftmost part of a declaration, then it applies to the
right. For consistency, I would therefore suggest that you drop the habit
of writing things like this:

const char* p;

in favour of this:

char const* p;

Now, you can read this from right to left, i.e. 'p' is a pointer to a
constant 'char'. Getting back to the above example, you then have

const void *pv1

which I would rather write as

void const* pv1

Then, you simply replace the placeholder type 'void' with the real type of
the array (I guess it's about sorting with qsort()), and that is 'char*'
(note: without any const!):

char* const* pv1

This then reads 'pv1' is a pointer to a const pointer to a 'char'. This
basically means that you can not redirect the pointer to anywhere else,
i.e. an expression like this will fail to compile:

*pv1 = "foo";

Note that I personally would have added another const:

char const* const* pv1

This then also prevents accidental modification of the string it points to,
but for the general principle of converting between typed and typeless
pointers and back this isn't necessary.


BTW:
Some really paranoid people would even have added another const there:

char const* const* const pv1

I wouldn't do so here, but in general it helps in other situations like
this:

float const pi2 = acosf(0.0f);
... // LOTS of code
... // use pi2 here

The point is that from the declaration you already _know_ that pi2 isn't
changed anywhere in between. Not only that, even if you tried to change it
accidentally, you would get a compiler error. The problem with this is that
many C compilers don't allow you (according to C89) to define variables in
the middle of a block, only at the beginning.

cheers

Uli
 
A

arnuld

Can you clarify this? What do you mean by "compile-time phenomenon"
and "run-time phenomenon"?


of course :) . This is just what I came to think of about types in C. If
am wrong, poke me in the eye ;)



<void*> points to no type, practically.

Lets us say that a C program asks the user for input, I can not enter some
words at standard input and make them of type <void>, they can be stored
in <array of char> but not in <array of void>. Section 13.8 of FAQ has a
function for comparing strings called <p_strcmp> which compiles fine
and takes 2 <const void*> as arguments. At run-time, for example, either
a <char*> or even a <char**> can be given as input and <void*> will
handle them gracefully but I can not give a <void*> to it as argument at
run-time. The input has to be of some type, to be useful to be processed
by the program.


Hence, <void> type exists at compile-time for the kind of input we do not
know the type of yet but at run-time I can not make any input as of
<void> type.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,764
Messages
2,569,565
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top