Even in C, you can write an abstraction for a growable buffer. The problem is, you have to make all the rest of the code work with it, rather than a char* or whatnot.
BoringSSL and libressl added CBS (bytestring) and CBB (bytebuilder) interfaces in 2015. Converting everything over is a chore, but that's exactly what those projects have been methodically doing over the years.
Unfortunately, I don't see those interfaces in OpenSSL 3.0, though maybe (hopefully) they're working toward something similar.
Then you have the new problem of restricting its growth and that adds a new failure mode to deal with. The C idiom works fine if you don't have implementation bugs.
Null terminated string is probably the worst data structure that was invented. It is has caused numerous security problems. It takes worst performance characteristics from array and linked lists (slow resizing, slow indexing). It definitely does not work fine.
Resizing arrays is such an annoying problem... because memory address space is flat. If only we had some sort of resizeable, non-overlapping by design segments, kind of like we have virtual memory mappings... but that'd completely kill address arithmetic. Oh well.