What's the preferred way to pass a string to and from a function?

The approach used by fgets() is a good way.

as a pointer

you don't have to pass it back, because the calling function already knows the pointer

of course, you may always pass back a pointer, if for example you are doing a search for a substring.

Passing back the original pointer is sometimes also used so that the function can be a nested function call. Example:

const char* foo(char *ptr)
{
    ...
    <snip>
    return ptr;
}

int main()   
{
     printf("%s\n", foo("How now brown cow."));
}