If you can populate the array at initialization time, making such pointers volatile type *const name and initializing them at variable/object declaration time, in the unit where the functions manipulating the structure are, you can similarly avoid the indirect load and have the functions generate machine code accessing the pointed-to structure directly (using its symbol, not through this structure).
Usually, the reason you use pointers is because you want the same code to work with different entities, different UART modules in this case. In such case the pointer cannot be optimized out.
I did think of an example where the array approach might be very useful: when creating an UART interfacing USB stick, with one serial endpoint being a control endpoint where you can use text commands –– terminal-like –– to configure the UARTs and other endpoints.
Very good example. For each converter, you would have a struct which contains pointers to endpoints, a pointer to UART, all the necessary settings, buffers, callback functions etc. The C functions would typically take that struct as a parameter. This way, the same code would work for all converters.
In OOP this would be called class instance.