Проблем по нахождению последнего отрицательного элемента и удалению нулей нету.

for(int i = 0; i < n; ++i)
Считать чётные элементы надо, то есть надо изменять переменную countEven: ++countEven % 2 == 0
Считать надо чётные элементы, то есть проверять чётность надо до проверки количества чётных: (arr[i] % 2 == 0 && ++countEven % 2 == 0)
Но основной недостаток кода в том, что постоянно перевыделяется память и перемещаются одни и те же элементы. При этом получается квадратичная сложность. int countToInsert = 0;
int countEven = 0;
for(int i = 0; i < n; ++i)
if(arr[i] % 2 == 0 && ++countEven % 2 == 0) ++countToInsert;
int n2 = n + countToInsert;
arr = realloc(arr, n2 * sizeof(*arr));
for(int i = n - 1; i >= 0; --i) {
arr[i + countToInsert] = arr[i];
if(arr[i] % 2 == 0 && countEven-- % 2 == 0) arr[i + --countToInsert] = lastNegative;
}
n = n2;
Тогда перед 6 должна стоять -7