Is there an easier way to work with pointers (sample code included)

  • Thread starter walter.preuninger
  • Start date
W

walter.preuninger

Is there an easier way to code the cmp procedure without going thru all
the pointer manipulations?

#include <stdlib.h>
#include <string.h>

int cmp(const void *i, const void *j)
{
void *p1, *p2;
char **s1, **s2;
p1=(void *) i;
p2=(void *) j;
s1=(void *) p1;
s2=(void *) p2;
return strcmp(*s1,*s2);
}

int main(void)
{
char string0[]="zebra";
char string1[]="hello";
char string2[]="goodbye";

char *base[3];

base[0]=(char *)string0;
base[1]=(char *)string1;
base[2]=(char *)string2;

printf("\nbase[0] %s",base[0]);
printf("\nbase[1] %s",base[1]);
printf("\nbase[2] %s\n",base[2]);

qsort(&base,3,sizeof(base[0]),(void *)cmp);

printf("\nbase[0] %s",base[0]);
printf("\nbase[1] %s",base[1]);
printf("\nbase[2] %s\n",base[2]);
}


TIA,

Walter
 
A

Al Balmer

Is there an easier way to code the cmp procedure without going thru all
the pointer manipulations?

#include <stdlib.h>
#include <string.h>

int cmp(const void *i, const void *j)
{
void *p1, *p2;
char **s1, **s2;
p1=(void *) i;
p2=(void *) j;
s1=(void *) p1;
s2=(void *) p2;
return strcmp(*s1,*s2);
}

int cmp(const void *i, const void *j)
{
char *s1 = i;
char *s2 = p;

return strcmp(s1, s2);
}
Is that what you're trying to do?

BTW, please properly indent code you post. Your compiler may not care,
but people reading it do.
 
M

Martin Ambuhl

Is there an easier way to code the cmp procedure without going thru all
the pointer manipulations?

In addition to an excessive number of useless casts, you have left out a
key header.
Yes, you are trying too hard. Compare the code below to your code,
which follows it:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int compare_strings(const void *i, const void *j)
{
return strcmp(*(char **) i, *(char **) j);
}

void showstrs(size_t n, char *s[n])
{
size_t i;
for (i = 0; i < n; i++)
printf("s[%u] %s\n", (unsigned) i, s);
}

int main(void)
{
char *base[] = { "zebra", "hello", "goodbye" };
size_t n = sizeof base / sizeof *base;
showstrs(n, base);
putchar('\n');
qsort(base, n, sizeof *base, compare_strings);
showstrs(n, base);
return 0;
}

[output]
s[0] zebra
s[1] hello
s[2] goodbye

s[0] goodbye
s[1] hello
s[2] zebra


[OP's code]
#include <stdlib.h>
#include <string.h>

int cmp(const void *i, const void *j)
{
void *p1, *p2;
char **s1, **s2;
p1=(void *) i;
p2=(void *) j;
s1=(void *) p1;
s2=(void *) p2;
return strcmp(*s1,*s2);
}

int main(void)
{
char string0[]="zebra";
char string1[]="hello";
char string2[]="goodbye";

char *base[3];

base[0]=(char *)string0;
base[1]=(char *)string1;
base[2]=(char *)string2;

printf("\nbase[0] %s",base[0]);
printf("\nbase[1] %s",base[1]);
printf("\nbase[2] %s\n",base[2]);

qsort(&base,3,sizeof(base[0]),(void *)cmp);

printf("\nbase[0] %s",base[0]);
printf("\nbase[1] %s",base[1]);
printf("\nbase[2] %s\n",base[2]);
}


TIA,
^^^
Are you a bill-collector or a script-kiddie?
 
R

Rouben Rostamian

Is there an easier way to code the cmp procedure without going thru all
the pointer manipulations?

#include <stdlib.h>
#include <string.h>

int cmp(const void *i, const void *j)
{
void *p1, *p2;
char **s1, **s2;
p1=(void *) i;
p2=(void *) j;
s1=(void *) p1;
s2=(void *) p2;
return strcmp(*s1,*s2);
}
[... the rest of the code snipped ...]

As a rule, the use of casts in a code is an indication that
something is wrong. There are exceptions to this rule, but in
general a cast should raise a red flag in your mind. Here is
a modified version of your code without casts. It is shorte
and should be easier to understand and debug:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int cmp(const void *a, const void *b)
{
char * const *aa = a;
char * const *bb = b;
return strcmp(*aa, *bb);
}

int main(void)
{
char string0[] = "zebra";
char string1[] = "hello";
char string2[] = "goodbye";
char *base[3];

base[0] = string0;
base[1] = string1;
base[2] = string2;

qsort(base, (sizeof base)/(sizeof base[0]), sizeof base[0], cmp);

printf("base[0] = %s\n",base[0]);
printf("base[1] = %s\n",base[1]);
printf("base[2] = %s\n",base[2]);

return EXIT_SUCCESS;
}
 
F

Flash Gordon

Al said:
int cmp(const void *i, const void *j)
{
char *s1 = i;
char *s2 = p;

Don't you mean:
const char *s1 = i;
const char *s2 = j;
return strcmp(s1, s2);
}
Is that what you're trying to do?

BTW, please properly indent code you post. Your compiler may not care,
but people reading it do.

Definitely.
 
K

Kenneth Brody

Al Balmer wrote:
[...qsort compare function on string array...]
int cmp(const void *i, const void *j)
{
char *s1 = i;
char *s2 = p;

return strcmp(s1, s2);
}
[...]

Any reason you can't simply do:

int cmp(const void *i, const void *j)
{
return strcmp(i,j);
}

--
+-------------------------+--------------------+-----------------------------+
| Kenneth J. Brody | www.hvcomputer.com | |
| kenbrody/at\spamcop.net | www.fptech.com | #include <std_disclaimer.h> |
+-------------------------+--------------------+-----------------------------+
Don't e-mail me at: <mailto:[email protected]>
 
M

Malcolm

Is there an easier way to code the cmp procedure without going thru all
the pointer manipulations?

#include <stdlib.h>
#include <string.h>

int cmp(const void *i, const void *j)
{
void *p1, *p2;
char **s1, **s2;
p1=(void *) i;
p2=(void *) j;
s1=(void *) p1;
s2=(void *) p2;
return strcmp(*s1,*s2);
}

int main(void)
{
char string0[]="zebra";
char string1[]="hello";
char string2[]="goodbye";

char *base[3];

base[0]=(char *)string0;
base[1]=(char *)string1;
base[2]=(char *)string2;

printf("\nbase[0] %s",base[0]);
printf("\nbase[1] %s",base[1]);
printf("\nbase[2] %s\n",base[2]);

qsort(&base,3,sizeof(base[0]),(void *)cmp);

printf("\nbase[0] %s",base[0]);
printf("\nbase[1] %s",base[1]);
printf("\nbase[2] %s\n",base[2]);
}


TIA,

Walter

Sorting a plain array of strings is usually pretty pointless.
Do something like this

typedef struct
{
char name[64];
char *description;
/* probably lots of other data associated with animals here */
} ANIMAL;

int cmp(const void *e1, const void *e2)
{
const ANIMAL *a1 = e1;
const ANIMAL *a2 = e2;

return strcmp(al->name, a2->name);
}

That's not too burdensome.
 
D

Default User

Is there an easier way to code the cmp procedure without going thru
all the pointer manipulations?

#include <stdlib.h>
#include <string.h>

int cmp(const void *i, const void *j)
{
void *p1, *p2;
char **s1, **s2;
p1=(void *) i;
p2=(void *) j;
s1=(void *) p1;
s2=(void *) p2;
return strcmp(*s1,*s2);
}


In addition to what all the others have said, you should almost NEVER
cast away const from a pointer. That's a major indicator that there's a
design flaw.



Brian
 
M

Micah Cowan

Default User said:
In addition to what all the others have said, you should almost NEVER
cast away const from a pointer. That's a major indicator that there's a
design flaw.

The exception would be when you're implementing something like
strchr(); where you want your parameter list to indicate a guarantee
that you won't change the string, but you don't want to force the
caller to make that same guarantee (or do the cast there).
 
P

Pierre Maurette

(e-mail address removed), le 08/03/2006 a écrit :
Is there an easier way to code the cmp procedure without going thru all
the pointer manipulations?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define AFFICHE printf("\nbase[0] %s""\nbase[1] %s""\nbase[2] %s\n",\
base[0],\
base[1],\
base[2])

typedef char* chaine;
typedef int(*f_comp_t)(const void*, const void*);


int cmp_chaine(const chaine* i, const chaine* j)
{
return strcmp(*i,*j);
}

int main(void)
{
char string0[]="zebra", string1[]="hello", string2[]="goodbye";
chaine base[] = {string0, string1, string2};
AFFICHE;
qsort(base,3,sizeof(chaine),(f_comp_t)cmp_chaine);
AFFICHE;
return 0;
}

Or:

/* .... */

int main(void)
{
char string0[]="zebra", string1[]="hello", string2[]="goodbye";
chaine base[] = {string0, string1, string2};
f_comp_t cmp = (f_comp_t)cmp_chaine;
AFFICHE;
qsort(base,3,sizeof(chaine),cmp);
AFFICHE;
return 0;
}
 
D

Default User

Micah said:
The exception would be when you're implementing something like
strchr(); where you want your parameter list to indicate a guarantee
that you won't change the string, but you don't want to force the
caller to make that same guarantee (or do the cast there).

I guess I'm not following. You can always pass a non-const pointer
through a const parameter. The caller wouldn't need to cast, nor would
the implementer.

In the previous code, the OP had const parameters and then blithely
cast the const away inside the function.



Brian
 
R

Richard Heathfield

Default User said:
I guess I'm not following. You can always pass a non-const pointer
through a const parameter. The caller wouldn't need to cast, nor would
the implementer.

No, think about strchr for a second (and don't worry too much about whether
I've got the implementation right - focus on the types):

char *strchr(const char *s, int ch)
{
char *p = (char *)s; /* either you cast it here... */
while(*p != '\0' && *p != ch)
{
++p;
}
if(*p == '\0')
{
p = NULL;
}
return p;
}

char *strchr(const char *s, int ch)
{
while(*s != '\0' && *s != ch)
{
++s;
}
if(*s == '\0')
{
s = NULL;
}
return (char *)s; /*... or you cast it here */
}
In the previous code, the OP had const parameters and then blithely
cast the const away inside the function.

Sure, and your point was perfectly valid. I think we're moving on a bit from
there now.
 
P

pete

Is there an easier way to code the cmp procedure without going thru all
the pointer manipulations?

#include <stdlib.h>
#include <string.h>

int cmp(const void *i, const void *j)
{
void *p1, *p2;
char **s1, **s2;
p1=(void *) i;
p2=(void *) j;
s1=(void *) p1;
s2=(void *) p2;
return strcmp(*s1,*s2);
}

int main(void)
{
char string0[]="zebra";
char string1[]="hello";
char string2[]="goodbye";

char *base[3];

base[0]=(char *)string0;
base[1]=(char *)string1;
base[2]=(char *)string2;

printf("\nbase[0] %s",base[0]);
printf("\nbase[1] %s",base[1]);
printf("\nbase[2] %s\n",base[2]);

qsort(&base,3,sizeof(base[0]),(void *)cmp);

printf("\nbase[0] %s",base[0]);
printf("\nbase[1] %s",base[1]);
printf("\nbase[2] %s\n",base[2]);
}

/* BEGIN new.c */

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

int cmp(const void *i, const void *j)
{
return strcmp(i, j);
}

int main(void)
{
char string0[] = "zebra";
char string1[] = "hello";
char string2[] = "goodbye";
char *base[3];

base[0] = string0;
base[1] = string1;
base[2] = string2;
printf("base[0] %s\n", base[0]);
printf("base[1] %s\n", base[1]);
printf("base[2] %s\n", base[2]);
putchar('\n');
qsort(base, sizeof base / sizeof*base, sizeof*base, cmp);
printf("base[0] %s\n",base[0]);
printf("base[1] %s\n",base[1]);
printf("base[2] %s\n",base[2]);
return 0;
}

/* END new.c */
 
A

August Karlstrom

Is there an easier way to code the cmp procedure without going thru all
the pointer manipulations?

#include <stdlib.h>
#include <string.h>

int cmp(const void *i, const void *j)
{
void *p1, *p2;
char **s1, **s2;
p1=(void *) i;
p2=(void *) j;
s1=(void *) p1;
s2=(void *) p2;
return strcmp(*s1,*s2);
}

int main(void)
{
char string0[]="zebra";
char string1[]="hello";
char string2[]="goodbye";

char *base[3];

base[0]=(char *)string0;
base[1]=(char *)string1;
base[2]=(char *)string2;

printf("\nbase[0] %s",base[0]);
printf("\nbase[1] %s",base[1]);
printf("\nbase[2] %s\n",base[2]);

qsort(&base,3,sizeof(base[0]),(void *)cmp);

printf("\nbase[0] %s",base[0]);
printf("\nbase[1] %s",base[1]);
printf("\nbase[2] %s\n",base[2]);
}

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define COUNT 3
#define MAX_LEN 32

char strings[COUNT][MAX_LEN] = {"zebra", "hello", "goodbye"};

void show(char strings[][MAX_LEN])
{
int k;

for (k = 0; k < COUNT; k++) printf("%s, ", strings[k]);
printf("\n");
}


int main(void)
{
show(strings);
qsort(strings, COUNT, MAX_LEN,
(int (*)(const void *, const void *)) strncmp);
show(strings);
return 0;
}


August
 
P

Peter Nilsson

pete said:
/* BEGIN new.c */

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

int cmp(const void *i, const void *j)
{
return strcmp(i, j);
}

int main(void)
{
char string0[] = "zebra";
char string1[] = "hello";
char string2[] = "goodbye";
char *base[3];

base[0] = string0;
base[1] = string1;
base[2] = string2;
printf("base[0] %s\n", base[0]);
printf("base[1] %s\n", base[1]);
printf("base[2] %s\n", base[2]);
putchar('\n');
qsort(base, sizeof base / sizeof*base, sizeof*base, cmp);
printf("base[0] %s\n",base[0]);
printf("base[1] %s\n",base[1]);
printf("base[2] %s\n",base[2]);
return 0;
}

/* END new.c */

One thing that AFAIK hasn't been pointed out in the thread is there is
no language guarantee that this will sort the strings into the order:

goodbye
hello
zebra
 
M

Malcolm

Richard Heathfield said:
No, think about strchr for a second (and don't worry too much about
whether
I've got the implementation right - focus on the types):

char *strchr(const char *s, int ch)
This is where the hacked in status of const as a late addition to the
language beocmes apparent.
const should taint everything it points to, and all pointers derived from
it. But that would be a major reengineering exercise.
 
J

Jordan Abel

This is where the hacked in status of const as a late addition to the
language beocmes apparent.
const should taint everything it points to, and all pointers derived from
it. But that would be a major reengineering exercise.

typeof would allow this, after a fashion:

#define strchr(x,c) (typeof x)strchr(x,c)
 
D

David Holland

> [...]
> int cmp(const void *i, const void *j)
> {
> return strcmp(i, j);
> }
>
> [...]
> char *base[3];
> base[0] = string0;
> base[1] = string1;
> base[2] = string2;
> [...]
> qsort(base, sizeof base / sizeof*base, sizeof*base, cmp);

Several people have posted code like this now, all apparently without
noticing that it's wrong.

base is an array of pointers to char. This is passed to qsort. qsort
calls cmp with two pointers, each of which points *to an element of
the array*.

Those void *'s in the argument of cmp are "really" char **, not char *,
and passing them to strcmp produces undefined behavior.

It so happens that you (and the OP) have laid out the program so that
on most platforms strcmp will reach a zero byte somewhere before
faulting, and the conventional layout of automatic storage is such
that strcmp interpreting the addresses as strings will generate the
expected output sort order, so just running the program once to check
it is misleading.

cmp needs to be

int cmp(const void *i0, const void *j0) {
const char *const *i = i0;
const char *const *j = j0;
return strcmp(*i, *j);
}

HTH.
 

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,995
Messages
2,570,230
Members
46,819
Latest member
masterdaster

Latest Threads

Top