Shouldn't s.ptr point to the heap data, like s1.ptr too?
s references to the data but don't own the data.
In my understanding, reference in Rust is like reference in C++
without the pointer syntax. Is it correct?
len(&self) is a method of the String type. The &self parameter means that it needs a reference to the stack-allocated¹ String to operate, which in turn contains a pointer onto the heap where the characters are stored.
In this case, s contains a pointer to s1 within main's stack frame, and s1 contains a pointer onto the heap. Inside String::len(), selfalso contains a pointer into main's stack frame (referring to s1), and it derefetences that pointer to read the len field (which is completely different from the len() method, despite sharing a name).
¹ The method doesn't really care which part of memory the String is stored in, but it's on the stack in this example.
It is not. s has type reference-to-String, so it points to a string, which in turn points to a heap buffer. The image in the book is correct.
What might have confused you is the "ptr" in s. There are of course no fields in references – references aren't structs, they are pointers, so the ptr is not a field of the type &String itself; the pointer is the address of the value where the reference points (which happens to be th address of s1 in the example).