It because every time
void pthread_exit(void *ret);
will be called from thread function so which ever you want to return simply its pointer pass with pthread_exit().
Now at
int pthread_join(pthread_t tid, void **ret);
will be always called from where thread is created so here to accept that returned pointer you need double pointer ..
i think this code will help you to understand this
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <stdlib.h>
void* thread_function(void *ignoredInThisExample)
{
char *a = malloc(10);
strcpy(a,"hello world");
pthread_exit((void*)a);
}
int main()
{
pthread_t thread_id;
char *b;
pthread_create (&thread_id, NULL,&thread_function, NULL);
pthread_join(thread_id,(void**)&b); //here we are reciving one pointer
value so to use that we need double pointer
printf("b is %s\n",b);
free(b); // lets free the memory
}