Hi I'm working with C and I have a question about assigning pointers.
struct foo
{
int _bar;
char * _car[SOME_NUMBER]; // this is meant to be an array of char * so that it can hold pointers to names of cars
}
int foofunc (void * arg)
{
int bar;
char * car[SOME_NUMBER];
struct foo * thing = (struct foo *) arg;
bar = thing->_bar; // this works fine
car = thing->_car; // this gives compiler errors of incompatible types in assignment
}
car and _car have same declaration so why am I getting an error about incompatible types? My guess is that it has something to do with them being pointers (because they are pointers to arrays of char *, right?) but I don't see why that is a problem.
when i declared char * car;
instead of char * car[MAXINT];
it compiles fine. but I don't see how that would be useful to me later when I need to access certain info using index, it would be very annoying to access that info later. in fact, I'm not even sure if I am going about the right way, maybe there is a better way to store a bunch of strings instead of using array of char *?
EDIT: I didn't mean to use INT_MAX (maximum value of int), it's just some other int, which is about 20.
car
and _car
are both arrays, and you cannot assign arrays in C (except when the array is embedded in a structure (or union) and you do a structure assignment).
They are also arrays of pointers to char, rather than pointers to arrays of char. What you have written in the code is probably what you want - you could store pointers to up to MAXINT names in the array. However, you should describe the type correctly - as an array of pointers to char or char pointers.
A pointer to an array of characters would look like:
char (*car)[MAXINT];
And a point to an array of character pointers (thanks, Brian) would look like:
char *(*car)[MAXINT];
Be careful of MAXINT; that could be a very large array (on Linux, <values.h>
defines MAXINT
as INT_MAX
, which is at least 231-1).
The code looks like:
struct foo
{
int _bar;
char * _car[MAXINT];
}
int foofunc (void * arg)
{
int bar;
char * car[MAXINT];
struct foo thing = (struct foo *) arg;
bar = arg->_bar; // this works fine
car = arg->_car; // this gives compiler errors of incompatible types in assignment
}
Neither the assignment to bar nor car should compile at all - arg
is a void *
. You presumably meant to use thing
in some shape or form. As Brian noted, there are problems there, too:
You either want:
int foofunc(void *arg)
{
int bar;
char *car[MAXINT];
struct foo thing = *(struct foo *)arg;
bar = thing._bar; // this works fine
car = thing._car; // this is still an array assignment
...other code using bar and car...
}
Or you want:
int foofunc(void *arg)
{
int bar;
char *car[MAXINT];
struct foo *thing = (struct foo *) arg;
bar = thing->_bar; // this works fine
car = thing->_car; // this is still an array assignment
...other code using bar and car...
}
Or, indeed:
int foofunc(void *arg)
{
struct foo *thing = (struct foo *) arg;
int bar = thing->_bar; // this works fine
char *car[MAXINT] = thing->_car; // this is still an array assignment
...other code using bar and car...
}
Finally, dealing with the array assignment, in C you can reasonably use memmove()
to do this:
int foofunc(void *arg)
{
struct foo *thing = (struct foo *) arg;
int bar = thing->_bar; // this works fine
char *car[MAXINT];
memmove(car, thing->_car, sizeof(car));
...other code using bar and car...
}
The similar function memcpy()
does not have reliable semantics if the areas to be copied overlap, whereas memmove()
does; it is simpler to always use memmove()
because it always works correctly. In C++, you need to be cautious about using memmove()
(or memcpy()
). In this code, it would be safe enough, but understanding why is non-trivial.
You do need to be aware that you are just copying pointers here - you are not copying the strings that the pointers point at. If something else changes those strings, it affects both the values seen via car
and the variable in the calling code.
One last point - for now: are you sure you need the argument to the function as a void *
? It opens up the code to all sorts of abuse which can be prevented if the function is declared to take a 'struct foo *
' instead (or even a 'const struct foo *
').
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With