I vettori "standard" sono strutture a dimensione prefissata, perché vengono allocati sullo stack e le loro dimensioni sono fissate al momento della compilazione. È certamente vero che si può allocare memoria a runtime con malloc e, nel caso in cui non basti, riallocarla con realloc.
Tuttavia quest'ultima soluzione è molto poco efficiente: mentre le liste concatenate allocano memoria man mano che aggiungi elementi, allocando ogni volta dei minimi blocchettini di memoria (contenenti il puntatore all'elemento precedente, il dato e il puntatore all'elemento successivo), quando tu vuoi aggiungere un elemento ad un vettore la realloc alloca nuova memoria per contenere tutto il vettore (incluso il nuovo elemento), ci copia il vettore da dove era prima e dealloca la memoria in cui era memorizzato prima il vettore. Inoltre se vuoi rimuovere un elemento da un array devi shiftare indietro di uno tutti gli elementi che lo seguono e richiamare la realloc dicendole che ti serve meno memoria (con tutte le perdite di tempo che questa funzione porta): un enorme spreco di tempo rispetto al funzionamento della lista concatenata, che si limita ad aggiornare due puntatori e dealloca un singolo blocchetto di memoria.