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.
You are creating a new array of size MAXINT. I think you want to create a pointer to an array of size MAXINT.
Creating a pointer to an array of char*'s:
The following is an array of size MAXINT to char* elements:
char * car[MAXINT];
The following is a pointer to: an array of size MAXINT to char* elements:
char* (*car)[MAXINT];
the following is how you set a pointer to: an array of size MAXINT to char* elements:
char* (*car)[MAXINT];
car = &arg->_car;
Other syntax errors in the question:
- You need to have a semicolon after your struct definition.
- You should be using
foo*
not foo
. So it should be:
struct foo* thing = (struct foo *) arg;
- You should be using
thing
not arg
:
bar = thing->_bar;
car = thing->_car;
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 *
').
You can't assign to an array the way you're doing. You can do an element-wise copy.
for(int i = 0; i < MAXINT; i++)
{
car[i] = (arg->_car)[i]
}
Note that if if the strings aren't constant, you may need to use strcpy
.
Array notation in C is legitimately confusing; your code doesn't mean what you think it means.
arg->_car
means "the address of the array _car
". Similarly, car
means "the address of the array car
". If you're trying to copy the contents of _car to car, then this will do it:
memcpy(car, _car, MAXINT);
But your real question, I think, is "what's the best way to store a list of strings?" This answer is: a dynamic list (one that grows automatically as you add items).
You'd declare it like this:
#define CARSIZE 65
int numCars = 0;
char **car; /* a list of addresses, each one will point to a string */
To add a car:
char *newCar = malloc(CARSIZE); /* make room */
strncpy(newCar, "Mercedes", CARSIZE); /* newCar has the address of the string */
car[numCars++] = newCar; /* store it */
To list the cars:
int n;
for (n = 0; n < numCars; ++n)
printf("%s\n", car[n]);
To remove the car at position n:
free(car[n]); /* release the memory */
/* condense the list of pointers */
for ( ; n < numCars - 1; ++n)
car[n] = car[n+1];
This is completely routine in C. NOTE: The above is off the top of my head and not copied from a working program, so I can't promise all the * are in the right place. I suspect this is a homework assignment, so I don't want to give you everything...