What's happening here is that even though v and p are different types, Vec<char> and &Vec<char> respectively, Rust allows you to often ignore this difference through convenience features such as an involved method resolution procedure that will automatically create or remove layers of indirection for the receiver if necessary, and a similar thing happens for indexing syntax, too. This way &v desugars to something like <Vec<char>>::index(&v), whereas &p becomes something like <Vec<char>>::index(p), so both things essentially call the same method with the same thing (a reference to v) and thus - unsurprisingly - result in the same reference (pointing to the same memory) as an output.
It's exactly the same as the difference between any other type and a reference to it. Vec isn't special. It's basically something like a 3-tuple or a struct with fields (buffer pointer, capacity, length), and so a reference to it is simply a reference to this struct or 3-tuple. There's nothing interesting about it.
You are printing the address of an element in the vector. Since Vec stores its elements on the heap, the address of the element doesn't depend on how you got there or how many levels of indirection the vector is behind. The vector doesn't physically contain its elements. Are you perhaps confusing Vec with statically-sized arrays?
Thanks for your kind response. I printed the memory addresses of v and p respectively, and both are pointing to different memory locations. p is assigned to the address of v, which points to stack memory, and v points to the address of a location in the heap of memory. Now, I'm unclear as to how both of the statements below yield the same memory address.
let x: &char = &v; // &(*v + 0) This points to heap address
let q: &char = &p; // &(*p + 0) This points to stack address
Because that's not what indexing means. It's not raw pointer arithmetic. (You can't perform pointer arithmetic on references anyway.) As it has already been explained by some previous posts, both forms are just syntactic sugar for Index::index(&v, 0), because method calls auto-reference if needed. So they call the exact same method with the exact same arguments, obviously yielding the exact same result. There's no pointer arithmetic on the address of the vector itself. At all.