In a pure stack, the only allowable operations are
Peek but in practical terms, that's not exactly true. Or rather, the
Peek operation often allows you to look at any position on the stack, but the catch is that it's relative to the one end of the stack.
So, as others have said, an array is random access and everything's referenced to the beginning of the array.
In a stack, you can only add/remove at the working end of the stack, but you still have random access read but it's referenced to the working end. That's the fundamental difference.
For instance, when you pass parameters on a stack to a function, the callee doesn't have to pop the parameters off to look at them. It just pushes local variables on the stack and references all the local variables and parameters based on an offset from the stack pointer. If you were using just an array, then how would the callee know where to look for its parameters? When the callee is done, it pops off its local variables, pushes a return value, returns control to the caller, and the caller pops the return value (if any), and then pops the parameters off the stack. The beauty is that it works no matter how far nested you are into your function calls (assuming you don't run out of stack space).
That's one particular use/implementation, but it illustrates the difference: array is always referenced from the beginning but stacks are always referenced from some working end position.
One possible implementation of a stack is an array plus an index to remember where the working end is.