One incorrect way which may seem to work would be to reinterpret the array using a pointer.
uint8_t array[4] = {0xd0, 0x69, 0x83, 0x3f};
float *p = (float*)array;
printf( "%f\n", *p );
However, this code has undefined behavior, because it violates the strict aliasing rule. It may also have alignment issues.
On the compilers gcc and clang, you can use __attribute__((__may_alias__)) on the pointer p, so that there is no strict aliasing violation:
uint8_t array[4] = {0xd0, 0x69, 0x83, 0x3f};
float __attribute__((__may_alias__)) *p = (float*)array;
printf( "%f\n", *p );
However, there still may be alignment issues.
A different way, which fully complies with the ISO C standard (and therefore should work on all compilers), would be to use memcpy instead:
uint8_t array[4] = {0xd0, 0x69, 0x83, 0x3f};
float f;
memcpy( &f, array, sizeof f );
printf( "%f\n", f );
Most compilers will optimize away the memcpy when compiler optimizations are active.
Beware of endianness issues, though. The posted code will only work on little-endian platforms.