char *s_gets(char * st, int n);
returns a pointer to char, while
char s_gets(char * st, int n);
returns a plain char.
I would like to ask also why is there a pointer in the function declaration in the first place? What is its purpose?
It indicates that the function returns a pointer value.  
C declaration syntax uses something called a declarator to convey the pointer-ness, array-ness, function-ness, or combination thereof of an item.  For example, take the declaration
int *p;
The type of p is int * (pointer to int).  The type is specified by the combination of the type specifier int and the declarator *p.  The int-ness of p is given by the type specifier int and the pointer-ness is given by the declarator *p.  
If you substitute p with f(void), you get
int *f(void); 
The type of f is "function returning pointer to int".  The pointer-ness and function-ness of f are specified with the declarator *f(void).  
For any type T and any declarator D, the following are true:
T D;        // D is an instance of T
T D[N];     // D is an array of T
T D();      // D is a function returning T
T *D;       // D is a *pointer* to T
T *D[N];    // D is an array of pointers to T
T *D();     // D is a function returning a pointer to T
T (*D)[N];  // D is a pointer to an array of T
T (*D)();   // D is a pointer to a function returning T
In both declarations and expressions, the postfix [] subscript and () function-call operators have higher precedence than unary *, so *a[N] will always be parsed as *(a[N]) (array of pointers).  To declare something as a pointer to an array or a pointer to a function, you need to explicitly group the * operator with the declarator using parentheses.  
Declarators can get arbitrarily complex:
T (*D())[N];      // D is a function returning a pointer to an array of T
T (*D[N])();      // D is an array of pointers to functions returning T
T *(*(*D)[N])[M]; // D is a pointer to an array of pointers to an array of pointers to T