First note declaration:
char *a = { "jhsa", "asndb", "drtfe", "nhurh", "bvhr"};
is incorrect it should be like:
char *a[] = { "jhsa", "asndb", "drtfe", "nhurh", "bvhr"};
That is array of char pointers. And each index in a[i]
points to an string literal.
The problem is in your comparison function. Your first two arrays are array of values whereas a[]
is an array of pointers.
read difference between char* str[]
and char str[][]
and how both stores in memory? to understand how memory organization of char* a[]
is different than char[][]
(a two dimension continue allocated memory organization).
What happens in compare_()
functions you passes address of a[i]
(but doesn't pass a[i]
it self). It works find when a[i]
is a values address e.g. for int[]
and char[][]
whereas in case of char*[]
you are not passing address of value instead passing address of address of value. I think your main confusion is between passing between 2D chars array char[][]
and and array of literal strings char*[]
.
First understand what are you passing to comparison function, suppose if you have following array then you are passing address of content x
, y
, z
(that are &a[i]) but not x
, y
, z
(that is a[i]).
a
+--------+
343 | |
| a[0]=x |
| |
+--------+
| |
347 | a[1]=y |
| |
+--------+
| |
351 | a[2]=z |
| |
| |
+--------+
* you are passing &a[i]
Now look at memory organization in case of char a[5][20]
, due to continue memory organization value of &a[i]
and a[i]
are same. Check following code and its output:
#include<stdio.h>
int main(){
char a[5][20] = { "jhsa", "asndb", "drtfe", "nhurh", "bvhr"};
int i = 0;
for(i = 0; i < 5; i++)
printf(
"&a[i] = %p, a[i] = %p, *a[i] = %c, string a[i] = \"%s\"\n",
(void*)&a[i], // you are passingg this &a[i]
(void*)a[i], // compare &a[i] and a[i] address value
*a[i],
a[i]
);
return 0;
}
Output:
$ gcc x.c -Wall -pedantic -o x
$ ./x
&a[i] = 0x7fff1dfb28b0, a[i] = 0x7fff1dfb28b0, *a[i] = j, string a[i] = "jhsa"
&a[i] = 0x7fff1dfb28c4, a[i] = 0x7fff1dfb28c4, *a[i] = a, string a[i] = "asndb"
&a[i] = 0x7fff1dfb28d8, a[i] = 0x7fff1dfb28d8, *a[i] = d, string a[i] = "drtfe"
&a[i] = 0x7fff1dfb28ec, a[i] = 0x7fff1dfb28ec, *a[i] = n, string a[i] = "nhurh"
&a[i] = 0x7fff1dfb2900, a[i] = 0x7fff1dfb2900, *a[i] = b, string a[i] = "bvhr"
Although &a[i]
and a[i]
are not same but value-wise same. To understand that are differences read Difference between &str
and str
, when str
is declared as char str[10]
?.
But value of &a[i]
and a[i]
are not same in case of char*[]
Check following code: y.c (similar to above x.c) and its output:
#include<stdio.h>
int main(){
char *a[] = {"jhsa", "asndb", "drtfe", "nhurh", "bvhr"};
int i = 0;
for(i = 0; i < 5; i++)
printf("&a[i] = %p, a[i] = %p, *a[i] = %c, string a[i] = \"%s\"\n",
(void*)&a[i],
(void*)a[i],
*a[i],
a[i]);
return 0;
}
output:
$ gcc y.c -Wall -pedantic -o y
$ ./y
&a[i] = 0x7fffa4674730, a[i] = 0x400690, *a[i] = j, string a[i] = "jhsa"
&a[i] = 0x7fffa4674738, a[i] = 0x400695, *a[i] = a, string a[i] = "asndb"
&a[i] = 0x7fffa4674740, a[i] = 0x40069b, *a[i] = d, string a[i] = "drtfe"
&a[i] = 0x7fffa4674748, a[i] = 0x4006a1, *a[i] = n, string a[i] = "nhurh"
&a[i] = 0x7fffa4674750, a[i] = 0x4006a7, *a[i] = b, string a[i] = "bvhr"
Now, notice values are different for &a[i]
and a[i]
(infact offset address values shows segments are different &a[i] get address space in stack whereas a[i]
gets address space where string literal stores, but that is different matter).
So, in string comparison function: int compare_string()
that statement return strcmp(c, d);
will not work for char*[]
and it should be something like return strcmp(*c, *d);
(although it was working for char[][]
where value of &[i]
and a[i]
are same first case I compiled code using -Wall
and -pedantic
it doesn't emits any warning so I believe no problem to use it as string address - but I am not sure too). And hence you need a separate version of compare_string_ for char*[]
in which you call strcmp(*c, *d);
. But now problem is function argument are cont void*
and dereferencing cont is undefined behaviour. To rectify your code I removed const
from every where and add a new function int compare_string_v2( void *a, void *b)
for char* a[]
as follows:
int compare_string_v2( void *a, void *b)
{
char **c = a;
char **d = b;
return strcmp(*c, *d);
}
just compile your code as: $ gcc code.c -Wall -pedantic -o code
it should work fine. Here you can check @working instance of code