Casting Const Void to String Errors - c

I have this line of code here where I am trying to type cast two void arguments as strings and then use the strcmp function to compare the two:
int compareFirstName(const void * p1, const void * p2)
{
const char **str1, **str2;
str1 = (char **) &p1;
str2 = (char **) &p2;
return strcmp(*str1, *str2);
}
However, I keep getting the error,
assignment from incompatible pointer type [-Werror]
str1 = (char **) &p1;
^
I am pretty sure I am casting right, so I do not know what the problem seems to be. Before, I had a segmentation fault error but resolved it and am now stuck here.
EDIT:
This is the struct I am using to compare the first names, IDS, and last names. Turns out I have to convert the void * into Student *, which I am a bit confused about
typedef struct
{
int ID;
char firstname[NAME_LENGTH] ;
char lastname[NAME_LENGTH] ;
} Student;

AFTER QUESTION EDIT:
int compareFirstName(const void * p1, const void * p2)
{
const Student *str1, *str2;
str1 = p1;
str2 = p2;
return strcmp(str1 -> firstname, str2 -> lastname);
}
/* the real cars is used here */
int compareFirstName1(const void * p1, const void * p2)
{
return strcmp(((const Student *)p1) -> firstname, ((const Student *)p2) -> lastname);
}
BEFORE EDIT
You are not trying to cast as "strings" only to pointer to pointer to char which has nothing in common with the C strings.
You also do not want to get the reference to the local parameters p1 and p2
You want:
int compareFirstName(const void * p1, const void * p2)
{
const char *str1, *str2;
str1 = p1;
str2 = p2;
return strcmp(str1, str2);
}
or just enough
int compareFirstName(const void * p1, const void * p2)
{
return strcmp(p1, p2);
}

Considering the question is slightly different than what it was before, I have decided to post a new answer:
int compareFirstName(const void * p1, const void * p2)
{
const Student *s1, *s2;
s1 = p1;
s1 = p2;
return strcmp(s1->firstname, s2->firstname);
}
This is the way to cast the void * arguments to the structs that you typedef'ed as Student. Then because p1 and p2 are pointers to structs, you need to use -> to access the members.

Related

Implement memcopy

I was asked to implement my own version of memcopy. This is what I found from the internet. The thing confuses me is that we have two void * pointers, why do we then typecast them onto char*?
Is this even correct?
// A C implementation of memcpy()
#include<stdio.h>
#include<string.h>
void myMemCpy(void *dest, void *src, size_t n)
{
// Typecast src and dest addresses to (char *)
char *csrc = (char *)src;
char *cdest = (char *)dest;
// Copy contents of src[] to dest[]
for (int i=0; i<n; i++)
cdest[i] = csrc[i];
}
The cast is needed because you may not dereference pointers of the type void *. Thus you may not for example to write src[i] when src is a pointer of the type void *. The type void is an incomplete type.
As for the function then it is wrong.
If you look at the declaration of the standard function memcpy you will see that it is declared like
void * memcpy(void * restrict s1, const void * restrict s2, size_t n);
^^^^^^ ^^^^^^^^^^^
Thus the function written by you should look at least like
void * memcpy(void *s1, const void *s2, size_t n);
The function definition can look as it is shown in this demonstrative program.
#include <stdio.h>
void * myMemCpy(void *s1, const void *s2, size_t n)
{
const unsigned char *src = s2;
unsigned char *dsn = s1;
while ( n-- ) *dsn++ = *src++;
return s1;
}
int main(void)
{
char s1[] = "Hello";
char s2[sizeof( s1 )];
puts( ( char * )myMemCpy( s2, s1, sizeof( s1 ) ) );
return 0;
}
The program output is
Hello
You need to typecast them because the "type" void doesn't have a size (mind void * does).
Then your loop will be able to move one char (ideally a byte) at a time.

getting at pointers in an array of struct passed as a void*

I have a function with a signature like qsort:
const char* get_str(int i, const void *base, size_t nmemb, size_t size);
I am passed arrays of pointers to const char*, or arrays of structs whose first field is a pointer to const char*.
What casts do I need to do to extract that pointer in the array element i?
I have tried casting the base as an array of char itself, so I can advance to the right element:
return *(const char**)(((const char*)base)[i * size]);
But the compiler is complaining: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
It looks like you want to implement a type or identification sytem for structs like so:
#include <stdlib.h>
#include <stdio.h>
struct a {
const char *id;
int x;
};
struct b {
const char *id;
double d;
};
union any {
struct a a;
struct b b;
};
int main()
{
struct a a[] = {{"one", 1}, {"two", 2}, {"three", 3}};
struct b b[] = {{"pi", 3.1415}, {"e", 2.71}};
union any any[3];
any[0].a = a[0];
any[1].b = b[0];
any[2].a = a[1];
puts(get_str(1, a, 3, sizeof(*a)));
puts(get_str(1, b, 2, sizeof(*b)));
puts(get_str(1, any, 3, sizeof(*any)));
return 0;
}
In this case, the following works:
const char* get_str(int i, const void *base, size_t nmemb, size_t size)
{
const char *p = base;
const char **pp = (const char**) (p + i * size);
return *pp;
}
This can be written in one line as:
const char* get_str(int i, const void *base, size_t nmemb, size_t size)
{
return *(const char**) ((const char *) base + i * size);
}
But I think that the detour via void pointers is not necessary. You can do the address calculations with the typed array:
puts(*(const char **) (&a[1]));
puts(*(const char **) (&b[1]));
puts(*(const char **) (&any[1]));
If you wrap that in a function:
const char *get_str(const void *str)
{
return *(const char **) str;
}
you get:
puts(get_str(&a[1]));
puts(get_str(&b[1]));
puts(get_str(any + 1));
which is more readable than the qsortish syntax in my opinion.
This works, because you acces only one element at a known position. The functions bsort and qsort, however, can't use this technique, because they have to access the array at several indices and hence must be able to do the index calculation themselves.
Find me (well, "yet another" but suppose this parentheses never existed!) a bug in that compiler and I give you a free cookie!
The compiler is right. This
*(const char**)(((const char*)base)[i * size]);
Will type-compile to something like (syntax: expresion -> type)...
base -> const void*
(const char*)base -> (const char*)const void*
(((const char*)base)[i * size]) -> *(const char*)const void* -> const char // Here's the problem!
(const char**)(((const char*)base)[i * size]) -> (const char**)const char // Now, this is *not* good...
*(const char**)(((const char*)base)[i * size]) -> *(const char**)const char -> const char* // Well, we have now just perfectly dereferenced '~'...
Not very sane, isn't it?*
BTW: You don't give us enough information for me to provide a full solution to your problem. What are those structs you talk about?
Edit: May this help you (written according to comments)?
*(const char**)&(((const unsigned char*)base)[size * i])

Pointer Initialization to Iterate through Array

I have a function, where I have 2 void pointers (part of the specification), but I know they are char *. I want to iterate through the char arrays, so I tried to create some pointers to iterate through them. When I do the following, my program doesn't work:
int foo(void const * first, void const * second)
{
char const * firstIt = (const char*) first;
char const * secondIt = (const char*) second;
...
}
However, if I do:
int foo(void const * first, void const * second)
{
char const * firstIt = *(const char**) first;
char const * secondIt = *(const char**) second;
...
}
What is the difference between the two and why does the second one work? I don't know if I included enough detail, so if more information is needed I'd be happy to provide it.
If the second one works, this is because the void pointer that you indicate for the function can really be anything, and I am guessing that you are passing to the function the pointer of a pointer. For example, the following code works:
#include <stdio.h>
#include <stdlib.h>
int foo(void const * first, void const * second);
int goo(void const * first, void const * second);
int main () {
char * a, * b;
a = malloc (sizeof (char));
b = malloc (sizeof (char));
*a = 'z';
*b = 'x';
goo (&a, &b); /* critical line */
free (a);
free (b);
return 0;
}
int foo(void const * first, void const * second) {
char const * firstIt = (const char*) first;
char const * secondIt = (const char*) second;
printf ("%c %c", *firstIt, *secondIt);
return 1;
}
int goo(void const * first, void const * second) {
char const * firstIt = *(const char**) first;
char const * secondIt = *(const char**) second;
printf ("%c %c", *firstIt, *secondIt);
return 2;
}
However, for the above program to work with the function foo you need to replace the critical line with a call of the form:
foo (a, b);
Does the difference make sense? Did it solve your problem?
The first approach assumes the caller has passed a char * (const qualified in some way).
The second assumes the caller has passed a char ** (const qualified in some way).
If the second one works, that means your caller is passing a char **.
The reason the first wouldn't work is undefined behaviour. Having a pointer of one type, converting to another type, and dereferencing it as anything other than the original type gives undefined behaviour. A round trip via a void pointer doesn't change that.
That is why compilers complain about implicit conversions of one pointer type to another (except to and from void pointers).

qsort an array of strings, compare

I am trying to figure out how to use qsort with an array of strings. My code looks like this.
char words[500][256];
int numOfWords; // this is calculated above
int sortWordList() {
int length = sizeof(words) / sizeof(char *);
qsort(words, length, sizeof(char*), compare);
}
int compare (const void * a, const void * b ) {
const char *pa = *(const char**)a;
const char *pb = *(const char**)b;
return strcmp(pa,pb);
}
However, I get a "Access violation reading location 0x###.." everytime and I dont know whats wrong. Can anyone spot my problem?
EDIT: Thanks for the wonderful help. You guys are always the best.
You are not casting your const void * to const char * properly, to do so, use instead:
const char *pa = (const char *)a;
const char *pb = (const char *)b;
Plus compare() should be above sortWordList() as you're using it in sortWordList().

Swapping 2 string pointers with a function whose parameters are void **

The following code doesn't compile:
void swap(void **p, void **q) {
void *tmp;
tmp = *p;
*p = *q;
*q = tmp;
}
int main(void) {
char *s[] = {"help" , "please"};
swap(&s[0], &s[1]);
return 0;
}
While this code compiles and runs just fine:
void swap(void **p, void **q) {
void *tmp;
tmp = *p;
*p = *q;
*q = tmp;
}
int main(void) {
char *s[] = {"help" , "please"};
swap((void **) &s[0], (void **) &s[1]);
return 0;
}
Why is the casting necessary ?
Yeah, so in addition to the already existing answers that point out that void ** is not the same as char **: your code invokes undefined behavior because of the incompatible pointer types. Here's what you actually want:
void swap(void *p1, void *p2, size_t size)
{
unsigned char buf[size];
memcpy(buf, p1, size);
memcpy(p1, p2, size);
memcpy(p2, buf, size);
}
And call it like this:
const char *s[] = { "help", "please" }; // also note the use of `const' for string literals
swap(&s[0], &s[1], sizeof(s[0]));
You have incompatible pointer assignment error in first code. In C type of a string literal is char[N] Where N is number of chars. Note in most of expressions char[N] easily decays into char*
According to your declaration char *s[] = {"help" , "please"}; type of s[i] is char* (actaully char[N] decayed into char*).
When you pass &s[i] then you are passing char** that is incompatible with void**. Second code works because you typecast into void** in function calling.
void* can be assigned any address type but its void** that has to be assigned address of void* type variable.
If you only having array of strings then in first version of swap function you can replace void by char then you can all without typecast.
The casting makes the example compile because of what you are passing the function.
char *var[]; is in many ways the same as char **var;
With that being said, you are passing the function a reference/address one of the members of the array (s[0]).
Another more prominent issue, is that the function accepts void pointers, and is passed character pointers (without the casting).

Resources