Let's start by talking about types.  In your main function, you declare err as
const char *err;
and when you call the set_error function, you pass the expression &err, which will have type "pointer to const char *", or const char **.  
However, in your function declaration and definition, you declare the parameter err as
int *err;
The types const char ** and int * aren't compatible, which is why the compiler is yakking.  C doesn't allow you to assign pointer values of one type to pointer variables of a different type (unless one is a void *, which is a "generic" pointer type).  Different pointer types are not guaranteed to have the same size or representation on a particular platform.
So that's where the compiler issue is coming from; what's the solution?
In C, string literals like "Error message" have type char *1 (const char * in C++), so whatever I assign it to needs to have a type of either char * or const char *.  Since we're dealing with a string literal, the latter is preferable (attempting to modify the contents of a string literal invokes undefined behavior; some platforms put string literals in read-only memory, some don't).  So you need to make the following changes to your code2:
void set_error( const char **err )
{
  *err = "Error message";
}
int main( void ) // you're not dealing with command line arguments, so for this
{                // exercise you can use `void` for your parameter list
  const char *err;
  set_error( &err ); 
  return 0;
}
Remember that C passes all function arguments by value; this means that the formal parameter err in set_error is a different object in memory than the actual parameter err in main; if the code had been 
void set_error( const char *err )
{
  err = "Error message";
}
int main( void ) 
{                
  const char *err;
  set_error( err ); 
  return 0;
}
then the change to err in set_error would not be reflected in the variable err in main.  If we want set_error to modify the value of err in main, we need to pass set_error a pointer to err and dereference it in the function.  Since the parameter err has type const char **, the expression *err has type const char *, which is the type we need for this assignment to succeed.  
1.  Actually, that's not true; string literals have type "N-element array of char", where N is the number of characters in the string plus the 0 terminator.  However, for reasons that aren't really worth going into here, the compiler will convert expressions of array type to expressions of pointer type in most circumstances.  In this case, the string literal "Error message" is converted from an expression of type "14-element array of char" to "pointer to char".
2.  A function definition also serves as a declaration; I typically put the called function before the caller so I don't have to mess with separate declarations.  It means my code reads "backwards" or from the bottom up, but it saves some maintenance headaches.