The simple answer is: Stack space is limited. You can expect to be able to allocate 1GiB on the heap, but you cannot expect to be able to allocate the same amount on the stack.
The first variant int x[size]; uses the stack. As such, you may find that your program crashes with a segfault if size is large. The allocation happens by simply decrementing the stack pointer register of your CPU. If you decrement it too much, the kernel will just view your next access to stack memory as an out-of-bounds access, and kill your process. It is not possible to detect this condition before actually being shot, or to recover from it in an orderly fashion. The kernel just shoots you without so much as a warning.
The second variant int* x = new int[size]; uses the heap. As such, you can expect the allocation to succeed as long as there is enough free RAM available to back the allocation. The operator new() will explicitly ask the kernel for the memory in an orderly fashion, and the kernel will either comply or signal unavailability of so much memory back in an orderly fashion. In the case of an error, the operator new() will proceed to throw an exception which you may catch and handle however you like.
Aside:
If your kernel is overcommitting its memory (like any modern Linux), you are not guaranteed to get an exception in case of an error. The kernel will just reply "ok" when operator new() asks it for the memory without actually providing any, and may later find that it cannot fulfill its promises. When that happens, it will invoke the OOM-killer (Out-Of-Memory killer), which shoots some processes based on some heuristic. So, never expect not to be shot for excessive memory consumption.
This is actually an optimization to be able to actually use all the available memory: For one thing, many programs do not actually use all the memory they allocate (like allocating a large buffer, but only using parts of it). For another, it is impossible to know which of the COW (Copy-On-Write) mapped pages will actually need copying. The kernel has no idea how much memory will be needed in the future, it only knows whether it currently has enough memory.
TL;DR:
Use int x[size]; only when you can prove that size will never exceed a small max value. If size is on the order of 10 to 100 (and the type itself is not insanely large), go for it. Use int* x = new[size]; in all other cases.