Отличие в применимости. Статически вы заранее определяете количество элементов. То есть в си Вы не можете написать char string[n]. Если заранее неизвестно кол-во выделяемой памяти, то ее приходится выделять динамически. С экземплярами классов то же самое.
Отличие при использовании в классе — ну Вы сами написали — в таком случае ее надо выделять в конструкторе и освобождать в дестректоре. Подводный камень — тогда надо писать свой конструктор копирования. Ибо дефолтный копирует все в лоб, в результате Вы получите 2 объекта, у которых Ваше поле ссылается на одну и ту же память. При уничтожении этих объектов получите ошибку (нельзя освободить одну область памяти дважды).
По поводу malloc/realloc — если старые данные уже не нужны, то лучше использовать realloc, а не free+malloc, так как память быстро фрагментируется и в скором времени приложение не сможет выделить нужный объем (malloc выделяет непрерывный блок памяти)