Когда вы используете ваши malloc, вы выделяете только первую позицию массива
arr[0] = (int*)malloc(sizeof(int) * w * h);
Это означает, что когда вам нужно освободить память, вам нужно вызвать free(arr[0])
изатем free(arr)
Это не даст вам ошибки.
Во всяком случае, я не думаю, что это то, что вы хотите сделать. Возможно, вы захотите найти решение в следующих строках:
int **arr = (int**)malloc(sizeof(int*) * h);
for (int i = 1; i < h ; ++i){
arr[i] = (int*)malloc(sizeof(int) * w); // with the correct size you want
}
Это позволит выделить h
указателей в массиве для использования, затем вы можете освободить память, как вы делали в своем примере
РЕДАКТИРОВАТЬ: Обратите внимание, что, как @AndrewHenle правильно указал в своем комментарии, это решение не выделяет true 2D массив, а просто массив указателей на массивы. Чтобы узнать, как правильно разместить 2D-массив, см. этот связанный вопрос