C pointers are represented in Fortran via the special opaque derived
type type(c_ptr) (with private components).  C pointers are distinct
from Fortran objects with the POINTER attribute.  Thus one needs to
use intrinsic conversion procedures to convert from or to C pointers.
For some applications, using an assumed type (TYPE(*)) can be
an alternative to a C pointer, and you can also use library routines
to access Fortran pointers from C.  See Further Interoperability of Fortran with C.
Here is an example of using C pointers in Fortran:
  use iso_c_binding
  type(c_ptr) :: cptr1, cptr2
  integer, target :: array(7), scalar
  integer, pointer :: pa(:), ps
  cptr1 = c_loc(array(1)) ! The programmer needs to ensure that the
                          ! array is contiguous if required by the C
                          ! procedure
  cptr2 = c_loc(scalar)
  call c_f_pointer(cptr2, ps)
  call c_f_pointer(cptr2, pa, shape=[7])
When converting C to Fortran arrays, the one-dimensional SHAPE argument
has to be passed.
If a pointer is a dummy argument of an interoperable procedure, it usually
has to be declared using the VALUE attribute.  void*
matches TYPE(C_PTR), VALUE, while TYPE(C_PTR) alone
matches void**.
Procedure pointers are handled analogously to pointers; the C type is
TYPE(C_FUNPTR) and the intrinsic conversion procedures are
C_F_PROCPOINTER and C_FUNLOC.
Let us consider two examples of actually passing a procedure pointer from C to Fortran and vice versa. Note that these examples are also very similar to passing ordinary pointers between both languages. First, consider this code in C:
/* Procedure implemented in Fortran.  */
void get_values (void (*)(double));
/* Call-back routine we want called from Fortran.  */
void
print_it (double x)
{
  printf ("Number is %f.\n", x);
}
/* Call Fortran routine and pass call-back to it.  */
void
foobar ()
{
  get_values (&print_it);
}
A matching implementation for get_values in Fortran, that correctly
receives the procedure pointer from C and is able to call it, is given
in the following MODULE:
MODULE m
  IMPLICIT NONE
  ! Define interface of call-back routine.
  ABSTRACT INTERFACE
    SUBROUTINE callback (x)
      USE, INTRINSIC :: ISO_C_BINDING
      REAL(KIND=C_DOUBLE), INTENT(IN), VALUE :: x
    END SUBROUTINE callback
  END INTERFACE
CONTAINS
  ! Define C-bound procedure.
  SUBROUTINE get_values (cproc) BIND(C)
    USE, INTRINSIC :: ISO_C_BINDING
    TYPE(C_FUNPTR), INTENT(IN), VALUE :: cproc
    PROCEDURE(callback), POINTER :: proc
    ! Convert C to Fortran procedure pointer.
    CALL C_F_PROCPOINTER (cproc, proc)
    ! Call it.
    CALL proc (1.0_C_DOUBLE)
    CALL proc (-42.0_C_DOUBLE)
    CALL proc (18.12_C_DOUBLE)
  END SUBROUTINE get_values
END MODULE m
Next, we want to call a C routine that expects a procedure pointer argument and pass it a Fortran procedure (which clearly must be interoperable!). Again, the C function may be:
int
call_it (int (*func)(int), int arg)
{
  return func (arg);
}
It can be used as in the following Fortran code:
MODULE m
  USE, INTRINSIC :: ISO_C_BINDING
  IMPLICIT NONE
  ! Define interface of C function.
  INTERFACE
    INTEGER(KIND=C_INT) FUNCTION call_it (func, arg) BIND(C)
      USE, INTRINSIC :: ISO_C_BINDING
      TYPE(C_FUNPTR), INTENT(IN), VALUE :: func
      INTEGER(KIND=C_INT), INTENT(IN), VALUE :: arg
    END FUNCTION call_it
  END INTERFACE
CONTAINS
  ! Define procedure passed to C function.
  ! It must be interoperable!
  INTEGER(KIND=C_INT) FUNCTION double_it (arg) BIND(C)
    INTEGER(KIND=C_INT), INTENT(IN), VALUE :: arg
    double_it = arg + arg
  END FUNCTION double_it
  ! Call C function.
  SUBROUTINE foobar ()
    TYPE(C_FUNPTR) :: cproc
    INTEGER(KIND=C_INT) :: i
    ! Get C procedure pointer.
    cproc = C_FUNLOC (double_it)
    ! Use it.
    DO i = 1_C_INT, 10_C_INT
      PRINT *, call_it (cproc, i)
    END DO
  END SUBROUTINE foobar
END MODULE m