Quick note: both are not arrays (in fact, C doesn’t have arrays at all).
Vector stores capacity and length additionally.
C code and Rust code do different things. C code, similar to the Rust one, would be calloc(sizeof(int), x). Rust code, similar to the C one, would he Vec::with_capacity(c).
No, there’s no additional indirection. A Vec<T> consists simply of the three parts: pointer to the data (*mut T), size (usize) and capacity (usize). This is also why methods such as Vec::from_raw_parts can exist (see the docs for the signature). The pointer points to a memory region for capacity-many values of type T, if the vector is full with length == capacity, then all of those are initialized.
The more “simple” dynamically-allocated-“array” type in Rust is Box<[T]>, by the way; this types does not have any unused capacity (hence that a capacity field is not needed and it consists only of the pointer and the length), so it’s comparable to an always-full Vec (and in fact, there’s cheap conversion functions between a full Vec<T> and a Box<[T]> in the standard library via the From trait).
At the low level, a Rust Vector is implemented in the exact same way – it allocates a memory region that's big enough for so many elements, and then operates over the returned pointer-to-buffer. Rust's Vec type is an RAII wrapper, so it manages this allocation automatically: the buffer will be freed and all items' destructors (if any) will be run when the vector goes out of scope, and when you push() to the Vec, it will reallocate and grow the buffer if necessary.
At the high level, you would probably use the Rust Vector for the same purposes as you would use a raw malloc()'ed buffer in C. Rust is a higher-level language, and its idioms differ from C, so it makes little sense to compare such details one-to-one. You could use a raw buffer pointer in Rust, too, but you wouldn't and shouldn't – in C, you're stuck with it as there's no better option.
First, there is a proper array type, spelled T[N] where N is an integer constant. It is possible to declare, for example, a pointer-to-array type, which is distinct from a pointer-to-pointer type.
Second, the array-to-pointer decay you are talking about is 1. not unconditional, and 2. does not mean that arrays would be the same as pointers, or that they wouldn't exist.
Array to pointer decay works in assignment and function argument position, for example. But in other contexts, e.g. when the argument of the sizeof operator, an array is absolutely, undoubtedly, an array. Demonstration.