1 void foo (const void *bar);
means that bar will definitly not be modified. While the foo author
could theoretically force to free or modify it, that would require casting the const away and whoever does it is on crack:
C uses call by value. So after invoking foo, which could do free ((void*)bar), and set its local copy of bar to NULL, the outer bar variable is undefined. Using it further will most likely result in a crash, including calling free (bar); in the outer frame again.
2 void foo (void **bar);
This is some sort of call by reference. You pass the address of the bar
variable, i.e. char *foobar = …; foo ((void **) &foobar); This syntax
ensures that the foo function can dereference its local copy of &foobar,
and make *bar (which is foobar) point to NULL after freeing, or
reallocate it – do all the pointer magic (except for pointer arithmetic,
because it is a void * pointer in this case).
3 void * foo (void *bar);
This will also work on the local copy of bar, and
– if it changes bar – return that changed value, i.e. the new address of its local bar copy. So you can invoke it
like char *foobar = …; foobar = foo (foobar);.
I’ve never seen any function acting like that, to be honest.
4 void * foo (const void *bar);
Just some flavor of 3, which will always return newly allocated memory
in addition to that already allocated for bar, while not modifying the
eel_str_strip_chr uses this variant.