Можно ли удалить пробелы в начале и в конце строки без создания нового массива?
Строковый литерал "  ab  " находится в особом сегменте данных, который (если процессор и ОС позволяют) только для чтения. А память сегмента данных освободить и сделать «кучей» нельзя.

Если предположить, что текст "  ab  " находится в «куче» — эта самая куча является сложной структурой данных и память выделяется с выравниванием. Потому функция realloc может (но не обязана) отдать конец или приделать память к концу. Отдать начало будет сложнее, и ни одна известная мне библиотека функций на это не способна.

Кроме того, Си++ придумал объект string_view именно для этого — чтобы передавать строки в функцию, абстрагируясь от выделения памяти и даже от оконечного нуля. Потому у string_view нет функции c_str().

Разумеется, вы можете сделать что-то вроде
char* str2 = str + 2;
str2[2] = '\0';
// А str оставь, уничтожать как-то придётся
Разумеется, если str находится в куче. Сегмент с литералами, напоминаю, только для чтения, и в ОС вроде DOS, где менять можно, такая замена может вызвать нехорошие побочки.
Освободить память нельзя, тем более, что при таком обьявлении выделение памяти происходит в куче. Обрезать строку можно - начальные пробелы срезаются просто перестановкой указателя, конечные - перестановкой символа '\0'.