Reputation: 1465
To compare string using library function, i learnt to write a comparison function to compare two strings, but im not really clear about why are they doing this.
int StrCmp(const void *a, const void *b){
char *s1 = *(char**) a;
char *s2 = *(char**) b;
return strcmp(s1,s2);
}
Why do they have to cast it to char ** first? why not just cast them to char * directly? like
return strcmp((char*)a, (char*)b);
Whats the meaning of casting ( a pointer) to ( a pointer to pointer) If i have
char *x = "string";
if i do casting for x
(char**)x; // what is this? Is this character 's'?
Im quite confuse with this, thanks for clarify and one more question is about the const if it is a const, can i still cast them?(altought i know i can)
Upvotes: 0
Views: 641
Reputation: 19333
This is effectively casting a void pointer (ie: void*
) to double pointer to char (ie: char**
).
Remember that the indirection/de-referencing operator (unary *
operator) and the type casting operator (eg: (char**)
) have the same precedence, but also right-to-left associativity.
So, consider the following:
void myFunction(void* a) {
char* s1; // Pointer to a character, or the beginning of a character array or string
// Note that the effective difference between a character array and a string is that
// a string is a character array that is terminated with the '\0' character
s1 = *(char**) a;
/* The above statement can be decomposed as follows:
* ( *( (char**) a ) )
* 1) Cast the pointer-to-void-type, (ie: void*)'a',
* to a pointer-to-pointer-to-char (ie: char**)
* 2) Deference the value, so it becomes a pointer-to-char
* 3) Assign this char* value to s1
*/
}
This is very common in C where you have to do some nifty pointer magic because the language does not support templates like its successor C++. Mind you, if you can work with advanced pointer logic, there's probably no need for you to use C++ in place of C anyways.
Good luck!
Upvotes: 1
Reputation: 7061
"Why do they have to cast it to (char pointer pointer) first? why not just cast them to (char pointer) directly?"
They have to cast it to what it is. Assuming the value coming in points to memory location 10,000, you have something like this:
(char **)
a address a
"points to"
*a **a
mem 1000 mem 10000 mem 20000
to mem 1007 to mem 10007
_____________ _____________ _______________
pointer var --> char pointer -> char
10000 20000 'a'
_____________ _____________ _______________
If you cast it to a (char *) you are telling the compiler that the address referred to by a (in this case 10,000) is a char. Which is not correct.
(char *) address a points
a to
mem 1000 mem 10000 mem 20000
to mem 1007
_____________ ______ ________________
pointer var --> "char" unreachable char
10000 ? 'a'
_____________ ______ ________________
"Whats the meaning of casting ( a pointer) to ( a pointer to pointer) If i have
char *x = "string"; if i do casting for x
(char**)x; // what is this? Is this character 's'?"
What exists in this example is something like:
x *x or x[0] x[1] x[2] x[3] x[4] x[5] x[6]
mem 15000 mem 30000 mem 30001 mem 30002 mem 30003 mem 30004 mem 30005 mem 30006
to 15007
char * char char char char char char char
_________ _________ _________ _________ _________ _________ _________ _________
30000 --> 's' 't' 'r' 'i' 'n' 'g' '\0'
________ _________ _________ _________ _________ _________ _________ _________
If you tell the compiler that x is a char** then it thinks this is the pattern:
x *x or x[0] **x
char *
mem 15000 mem 30000 "char"
to 15007 to 30007
__________ _________ _________
30000 --> "string\0?"
converted to
pointer value -> ??
__________ _________ _________
It incorrectly ends up going to whatever "address" the first 8 bytes starting at 30000 resolves to and getting a "character". But since 30000 is the start of a null-terminated character array, at best it goes to some part of memory and gets some random byte, thinking it is a valid char. At worst it will get an address that is invalid for this program, causing a fatal error when it tries to access it.
so can i just do
return strcmp((char *)a, (char *)b);
No, because a and b are not char pointers. To get char pointers you can't avoid:
return strcmp( *(char**)a, *(char**)b);
Using Linden's example you would call like so:
#include <stdio.h>
#include <string.h>
int StrCmp(const void *a, const void *b){
char *s1 = *(char**) a;
char *s2 = *(char**) b;
printf("s1:%s\n",s1);
printf("s2:%s\n",s2);
return strcmp(s1,s2);
}
const char* arr_of_ptr[] =
{
"hello",
"world"
};
const char **p_arr_of_ptr = arr_of_ptr;
int main(void)
{
const char *cstring1 = "LaDonna";
const char *cstring2 = "McPherson";
const char **pcstring1 = &cstring1;
const char **pcstring2 = &cstring2;
StrCmp(&arr_of_ptr[0],&arr_of_ptr[1]);
StrCmp(pcstring1,pcstring2);
StrCmp(p_arr_of_ptr,p_arr_of_ptr + 1);
}
Upvotes: 4
Reputation: 213842
Most likely the caller of that function is using an array of pointers, such as:
const char* arr_of_ptr[] =
{
"hello",
"world"
};
In that case, the first element of the array is a pointer to a char, it is not a char in itself. Therefore the StrCmp function acts as a translator between the array of pointers to normal C strings.
However, they are also casting away the const keyword, which is bad practice. The function should be written like this:
int StrCmp(const void *a, const void *b){
const char *s1 = *(const char**) a;
const char *s2 = *(const char**) b;
return strcmp(s1,s2);
}
Upvotes: 4