First, a() is declared as returning void, but you attempt to return a char*. Change the signature to return a char*.
Second, your function is fine, but your example code has a memory leak because you never free the memory that the returned pointer points to.
Third, as gbrandt pointed out, you are not checking for success after the call to malloc. malloc can fail, and checking to see if it did is a good habit to get into.
Another way to accomplish this would be to pass a pointer to a pointer into a() instead, and then the caller has to create the pointer themselves before passing it to a(), but either way you still need to free the memory. To be honest, I would go with your approach over this in this case. There is no compelling reason to do it this way, just thought I would mention it.
void a(char **p)
{
*p = malloc(8);
if (*p)
{
**p[0] = 'a';
**p[1] = 'b';
...
**p[7] = 'h';
}
}
int main(void)
{
char *x;
a(&x);
//do something with x
.....
free(x);
}
If this alternate approach confuses you, please let me know as I would be happy to provide an explanation (though, at the moment, I need to get back to work!)