so i'm diving into multithreading in c via POSIX pthreads but i do really struggle with the general concept of pointers and their referencing and dereferencing mechanisms.
One of the parameters in
pthread_create(...,pthread_attr_t *attr,...)
is a function pointer.
This function is usually declared like this:
void *thr_func(void *arg){
thread_data_t *data = (thread_data_t *)arg;
...
}
thr_func is a function pointer, so usually i use a function pointer to reference to an existing, implemented function via &, e.g.:
thr_func = &thr_func_impl;
while the arguments of thr_func are also pointers dereferenced for example via * to retrieve the values they are pointing to.
What I don't understand is the following:
when i create a thread, why do i just give the function name in pthread_create(...,thr_func,...) instead of its address so that it can be used, e.g.: pthread_create(...,&thr_func,...) or is this done by pthread_create() already ?
How do i have to understand this part:
thread_data_t *data = (thread_data_t *)arg; okay i want to dereference a
structure of type thread_data called data via thread_data_t *data = ... .
Shouldn't i do it this way:
thread_data_t *data;
data = &arg; /* now * on data ,e.g.: *data == struct-data (dereferencing) gives the struct data and data without * just gives the structs start address */
-> I cannot really follow the things happening inside:
void *thr_func(void *arg){
thread_data_t *data = (thread_data_t *)arg;
...
}
I'd be glad if somebody had a good explanation, thanks!
Passing the function name as a parameter is equivalent to passing its address using the & operator. I.e. pthread_create(...,thr_func,...) and pthread_create(...,&thr_func,...) are interchangeable. This has nothing to do with pthreads, it is a language construct.
arg is a pointer of type void. In order to cast it to a pointer of type thread_data_t you should do (thread_data_t *)arg. By using thread_data_t *data = &arg you are attributing the address of arg itself to data, not the address arg is pointing to.
Consider the following:
int my_int = 7;
void *my_void_ptr = &my_int;
int *my_int_ptr = (int *)my_void_ptr; // Just a cast, points to my_int
printf("%d", *my_int_ptr); // 7
int *my_int_ptr2 = &my_void_ptr; // int pointer to the address of my_void_ptr, issues a warning
printf("%d", *my_int_ptr2 ); // The address of my_void_ptr as an integer
Finally, pthreads stands for POSIX threads, so "POSIX pthreads" is redundant.
For the first question, a function will naturally decay to a pointer to itself, similar to the way that arrays decays to a pointer to its first element.
So if you have a function
void *thr_fun(void *arg) { ... }
then you can pass a pointer to it using either &thr_fun which is the explicit and (some would say) "correct" way. The other is to use plain thr_fun as it will decay to &thr_fun anyway. So in C it's really a question about style and personal preference.
For your second question, remember that void * is a generic pointer that can point to anything but it doesn't have any explicit type. Therefore you can't dereference it (since a dereferenced void * would have the type void).
That's the reason you need to cast it.
And no you should not get the address of the pointer, since that will give you a pointer to the pointer.
Related
I am trying to pass struct to thread. Unfortunatelty when it happens i can no longer use p[i][j]. I am getting error: subscripted value is neither array nor pointer nor vector
typedef struct MY_M {
int *p1;
int *p2;
} MY_M;
int *M1[r];
for (i=0; i<r; i++){
M1[i] = (int *)malloc(c * sizeof(int));}
pthread_t thread1;
struct MY_M *p = malloc(sizeof(struct MY_M));
p-> p1 = *M1;
p-> p1 = *M2;
int ret = pthread_create(&thread1,NULL,thread,(void*) p);
thread here:
void* thread(void* parameter )
{
MY_M **p = (MY_M*)parameter;
p->p1[0][0] = 5;
}
When i comment p[0][0] the program is working fine. Why it is not working? I would be grateful for any help.
I can't tell exactly what you are trying to accomplish here, but I can see a number of errors.
In the first place, you assign two values to p->p1. I assume this is probably a mistake and you meant to assign one value to p->p1 and another to p->p2. (And where did M2 come from?)
Second, int *M1[r]; will allocate r pointers to int on the stack, which means the array containing the buffers will become invalidated shortly after the function returns.
You are also dereferencing M1 during assignment, which means you are only pointing to the first buffer that you allocated. Again, I can't tell exactly what you are trying to do with that, so I don't know what to recommend.
p1 is also type int*, which means it contains the address of an int, so it can only be dereferenced once and will resolve to int. If you want to dereference it twice (p->p1[x][y]) it should be type int** or pointer to some other dereference-able type.
Also, you cast parameter to MY_M*, but then assign it to a variable of type MY_M**. That is not correct (in fact, isn't that giving you a compiler error?)
As far as I can tell, you are simply trying to allocate some structure that your thread will later have access to. If that is the case, the code would be something like this:
typedef struct MY_M {
int* p1;
int* p2;
} MY_M;
MY_M* p = (MY_M*)malloc( sizeof(MY_M) );
p->p1 = (int*)malloc( c * sizeof(int) );
p->p2 = (int*)malloc( c * sizeof(int) );
pthread_t thread1;
int ret = pthread_create(&thread1, NULL, thread, (void*)p);
thread here:
void* thread(void* parameter)
{
MY_M *p = (MY_M*)parameter;
p->p1[0] = 5;
}
Overall, it seems that you don't fully understand pointers properly. I can try to give a brief rundown, but do consult other guides and references to fully understand the concept.
First: a pointer is an address. So int* a = &b; means that a of type int* will contain b's address, and therefore it points to b. If you dereference a pointer, that means you take the address value that it holds and follow the address to its original source. So *a dereferences a, resolving to the value stored in b.
Array index syntax is equivalent to offset + dereferencing, so when you say p->p1[0][0], that is really equivalent to *((*(p->p1+0))+0), which dereferences the variable twice.
You can't dereference something that isn't a pointer (i.e., doesn't contain an address). That's why your int* can't be dereferenced twice. After dereferencing it once, it is now an int, which does not contain an address and cannot be dereferenced.
I hope this helps.
What you're actually using is an array of pointers (to arrays), rather than a proper 2D array -- though that isn't really a problem here. As for why it isn't working, you simply have the wrong type for p in your thread function -- it should be int ** rather than int *.
I have a question for the exact meaning of a pointers phrase.
I have the following method:
myFunc(const void * p)
{
...
}
And it is being called by:
myStruct *st;
...
myFunc((char **)&st->arr);
I have experience with pointers, but in this case I still get lost with all these pointers and casting..
Can I get please an accurate explanation about how this case works?
Thanks
This seams to be bad quality code! Maybe not dangerous, as const appears in prototype.
myFunc(const void * p) accepts a pointer to anything and const should mean it won't touch it.
Now, st is a pointer to myStruct, so st->arr is the value of arr member and &st->arr is memory address of arr member. Assuming arr is an array, st->arr value is already a pointer.
So, (char**) is possibly the correct type of &st->arr, it is a pointer to a character array. And if it is the correct type, there is no need to cast!
You cast when you need to tell the compiler to handle your data as another data. It would make sense, in this case myFunc((const void *)&st->arr);
Anyway, without further information on myFunc, I belive that true programmer intention was myFunc((const void *) st->arr);
the address of st->arr is being converted to a char** (i.e. the address where to find a pointer to a char). myFunc accepts pretty much anything (void*) and you must be careful to pass it something it knows how to handle.
Internally, myFunc can do something like this:
struct myStruct{
char* arr;
};
void myFunc(const void* ptr){
char** cPtr = (char**) ptr;
(*cPtr)[1] = ...;
}
int main()
{
struct myStruct s;
...
myFunc((char **)&s.arr);
...
}
However, you should notice that this is extremely bad (as in "dangerouse") code.
You are calling the method myFunc with a double pointer char ** and the same you are catching with the const void *ptr . In C a void pointer can hold the other pointer types like(char */float */int */...), later on we can typecast them when we are using.
So here a void pointer can able to hold a double character pointer and you can typecast the void pointer to a double character pointer later on like
char **tempPtr = (char **)p;
Here const qualifier makes the pointer p as a constant data pointer, which means inside the function it wont change the data it is pointing to.
I have to implement a wrapper for malloc called mymalloc with the following signature:
void mymalloc(int size, void ** ptr)
Is the void** needed so that no type casting will be needed in the main program and the ownership of the correct pointer (without type cast) remains in main().
void mymalloc(int size, void ** ptr)
{
*ptr = malloc(size) ;
}
main()
{
int *x;
mymalloc(4,&x); // do we need to type-cast it again?
// How does the pointer mechanism work here?
}
Now, will the pointer being passed need to be type-cast again, or will it get type-cast implicitly?
I do not understand how this works.
malloc returns a void*. For your function, the user is expected to create their own, local void* variable first, and give you a pointer to it; your function is then expected to populate that variable. Hence you have an extra pointer in the signature, a dereference in your function, and an address-of operator in the client code.
The archetypal pattern is this:
void do_work_and_populate(T * result)
{
*result = the_fruits_of_my_labour;
}
int main()
{
T data; // uninitialized!
do_work_and_populate(&data); // pass address of destination
// now "data" is ready
}
For your usage example, substitute T = void *, and the fruits of your labour are the results of malloc (plus checking).
However, note that an int* isn't the same as a void*, so you cannot just pass the address of x off as the address of a void pointer. Instead, you need:
void * p;
my_malloc(&p);
int * x = p; // conversion is OK
Contrary to void *, the type void ** is not a generic pointer type so you need to cast before the assignment if the type is different.
void ** ptr
Here, "ptr" is a pointer to a pointer, and can be treated as a pointer to an array of pointers. Since your result is stored there (nothing returned from mymalloc), you need to clarify what you wish to allocate into "ptr". The argument "size" is not a sufficient description.
I need some help in C syntax, more about C casting syntax.All information I found in web is about simple casts like (int) or (char) etc...I always get stuck in casting void* to a array or multi-dimentisional array or pointers of such things, but I never know how to do that! All that I do in these cases was trying things like (char []) or (char *[]) or (*char []) without any idea what I'm doing, until I get no errors about type casting.
Anybody have a thumb of rule to follow or some tips or tricks to do that?For example I have a arry of void pointers and I pass it to a function, how to turn it into array again?
main () {
int data1, data2;
char data3, data4;
void *function_data[] = {data1, data2, data3, data4};
some_function (function_data);
return;
}
some_function (void *data) {
void *function_d[4];
function_d = (void *[]) data; //It not work, how to cast data?
}
EDIT: I wrote wrong, I thinked that it wasn't important, so, I changed the variables data* of my code for better undestand.
Your problem is that void *function_d[4]; creates new array. You cannot assign other array to it. function_d should be of type void**.
The basic idea is to use the type definition of the intended type without the variable name and placed in parentheses as a cast to that type. For example:
int c;
c = (int) 4;
and
char * (*functionptr)(float, double);
functionptr = (char * (*)(float, double))myfunction;
Of course always assuming the type cast is possible and makes sense. Be aware: C doesn't prevent most nonsensical casts, so you'll have to take care yourself.
In your case, function_data is defined to be an array of pointers to void. Therefore, each data needs to be of type void **, as Keith already indicated.
By calling some_function with function_data as parameter, you're passing a pointer to function_data[0] into the function.
In order for your function to use it again as an array of 4 pointers to void, you would need to use a cast like you did, (void*[]). However, the array function_d is an array reserving also the space for four pointers, and you cannot change the function_d pointer (it is of type void * * const!). To do what you seem to want, you'll need a non-const pointer, like
void * * function_d = (void*[])data;
You may then still use it in the same way like function_data, using subscription like an array. function_d[2] will give you the value equal to *data3.
You cannot assign to an array object.
How are data1, data2, data3, and data4 declared?
void* is (or can be used as) a generic pointer type. That can give you tremendous flexibility, but it can also inhibit type checking.
function_data is an array of 4 pointers to void. In the call some_function (function_data), it's implicitly converted to void**, a pointer to the first element.
some_function expects a void*, not a void** -- but any pointer type (other than a function pointer) can be implicitly converted to void*, so the compiler doesn't complain about the call.
Here's a version of your program that's at least type-correct (I think).
#include <stddef.h>
void some_function(void **data, size_t count);
int main(void) {
void **data1, **data2, **data3, **data4;
void *function_data[] = { *data1, *data2, *data3, *data4 };
some_function (function_data,
sizeof function_data / sizeof function_data[0]);
return 0;
}
void some_function(void **data, size_t count) {
size_t i;
for (i = 0; i < count; i ++) {
/*
* do something with data[i], which is of type void*
*/
}
}
Note that data1 and friends are not initialized, so this program's behavior is undefined. I suspect you meant to write something like:
void *function_data[] = { &data1, &data2, &data3, &data4 };
but it's hard to tell just what you're trying to do.
If you really need the function to have a copy of the array, you can use memcpy() (you can't assign array values). For most purposes, though, it makes more sense to use pointers to access the original array. You'll need to make a copy if you want to modify the copy without affecting the original.
And I've corrected the declarations for main and some_function, and added a declartion for some_function to the top so it's visible when you call it.
You should always explicitly declare the return type for all your functions. In the 1990 version of C, you can omit it, and it will default to int (but it's still better to declare it as int explicitly). In the 1999 version of C, the type is required, and you can't call a function without a visible declaration.
Again, it's hard to tell from the code you've shown us just what you're trying to do, which makes it difficult to guess how to do it.
Several issues:
This isn't going to work:
int data1, data2;
char data3, data4;
void *function_data[] = {data1, data2, data3, data4};
because int and char are not compatible with void *. You could fix this as follows:
void *function_data[] = {&data1, &data2, &data3, &data4};
because int * and char * are compatible with void *.
When you pass function_data to some_function, the array expression is converted to a pointer value, so what some_function receives is a void **. You can use the subscript operator on the pointer as though it were an array:
some_function(function_data);
...
void some_function(void **data)
{
int *x = data[0]; // remember, we stored the *addresses*
int *y = data[1]; // of data1, data2, data3, and data4;
char *a = data[2]; // since the type of data is void **,
char *b = data[3]; // the type of data[i] is void *.
...
}
IOW, you don't need to cast data to an array type in order to use it like an array.
I am trying to allocate an array of structs within a function.
My struct is as follows:
typedef struct{
uint16_t taskNumber;
uint16_t taskType;
double lat;
double lon;
double speed;
uint8_t successCriteria;
uint16_t successValue;
uint8_t nextPoint;
}missionPoint;
In my code I declare a missionPoint-pointer which I then pass into the function that will dynamically allocate it after parsing a file and figuring out how big it needs to be.
Currently this is how my code looks:
missionPoint* mission; //declaring the pointer
parseMission(mission);
The parseMission function will then parse a specific file and find out how many missionPoints I need and will then allocate it in the following manner:
mission = (missionPoint*) malloc(n * sizeof(missionPoint));
where n is the parsed number of missionPoints I need.
The problem is that within the function I can see the proper values but not outside of it; once the function returns it's like nothing happened.
I would appreciate your help in making it so that the function modifies the original pointer and I can see the data from outside the function.
You need to pass a reference to the pointer, i.e. a double pointer, because the address itself is going to be modified:
missionPoint *mission;
parseMission(&mission);
The argument of parseMission should now be of type missionPoint ** instead of missionPoint *:
*mission = (missionPoint*) malloc(n * sizeof(missionPoint));
This wouldn't be necessary if you only wanted to modify the memory mission is pointing to, but it cannot be avoided since you are assigning a new value to the pointer itself.
Also note that casting the return value of malloc is not necessary in C.
Pass a reference (i.e. pointer) to the mission pointer rather than the value of the mission pointer itself. So the declaration of your function would look like:
void parseMission(missionPoint** pointer_ref);
rather than:
void parseMission(missionPoint* pointer_val);
then pass the address of mission (i.e., &mission) as the argument value for parseMission.
Think that a pointer in C is just a integer, storing some memory address.
Think that malloc allocates some memory and returns you the address of this memory (a new pointer).
Understand that this snippet will print "2", regadless of what the called function does with the passed value.
int a = 2;
doSomething(a);
printf("%d\n",a);
Once you understand all this, you can predict what this code will produce, and why you need to pass the "reference to the pointer" (pointer to the pointer) instead of of the pointer itself (value of the pointer) to your allocator function.
void remalloc(char * p1) {
printf("pointer before remalloc (inside function): %X\n",(unsigned int)(p1));
free(p1);
p1 = (char*)malloc(200000);
printf("pointer after remalloc (inside function): %X\n",(unsigned int)(p1));
}
int main(){
char * p;
printf("pointer before malloc: %X\n",(unsigned int)(p));
p = (char*)malloc(10);
printf("pointer after malloc: %X\n",(unsigned int)(p));
remalloc(p);
printf("pointer after remalloc: %X\n",(unsigned int)(p));
}