int arr[N]; goes either into static memory if it's in filescope (or is preceded by static) or on the stack.
A static-memory int arr[N]; is cheapest to allocate (both in terms of size overhead and allocation time) but it can never be freed and the memory won't always be cache-local.
If the int arr[N]; is inside a block (and not preceded by static), int arr[N]; goes on the stack. This memory will pretty much certainly be cache-local, but you might not wish to use this form if N is large and your stack is limited (or you're risking stack overflow) or if the lifetime of arr needs to exceed that of its containing block.
malloc'd memory takes some time to allocate (tens to hundreds of ns), it may carry some size overhead, and the allocation may fail, but you can free the memory later and it stays until you do free it. It might also be resizable (via realloc) without the need to copy memory. Cache-locality-wise, it's sort of like static memory (i.e., the block may be potentially far from the cache-hot end of the stack).
So those are the considerations: lifetime, stack size, allocation time, size overhead, free-ability, and possibly cache-locality.
A final consideration might be a peculiar feature of C: effective type. A declared array has a fixed effective type and therefore cannot be retyped without violating C's strict aliasing rules but malloc'd memory can be. In other words, you can use a malloc'd block as a backing storage for a generic allocator of your own, but a declared char array cannot be used that way, strictly speaking.