1

i need some help with understanding of rust basics and memory basics at all. I think this will be helpful for those who come across this after me.

memory adress

(1) Here i create a function thats return pointer to a vector. Why there is two different adresses if there must be the same pointer?

fn get_pointer(vec: &[i32]) -> &[i32] {
    vec
}
fn main() {
    let vector = vec![1, 2, 3, 4, 5];

    let first_element = get_pointer(&vector);
    let vector: Vec<String> = Vec::new();
    println!(
        "Vector: {:p}, and func result: {:p}",
        &vector, first_element
    );
}

Output: Vector: 0x5181aff7e8, and func result: 0x17e5bad99b0

different adresses of one element?

(2) Now im creating a function thats return a pointer to the first element of a Vector

fn get_pointer_to_first_element(vec: &[i32]) -> &i32 {
    &vec[0];
} 

fn main() {
    let vector = vec![1, 2, 3, 4, 5];

    let first_element = get_pointer_to_first_element(&vector);

    println!(
        "from variable: {:p}, from function: {:p}",
        &vector[0], &first_element
    );
}

from variable: 0x1f9a887da80, from function: 0x15fe2ffb10

variables defined in functions

(3) Okay, i understand thats question is even more stupid, but i realy cant get it.

Here i create a pointer variable inside a function, and it must be deleted with its "value" when program leaves scope of a function, so why i can use that value after call of the function?

also bonus question about deleting value after shadowing, is that true? Why?

fn get_pointer_to_first_element(vec: &[i32]) -> &i32 {
    let pointer = &vec[0];
    pointer
} // here variable "pointer" and its value must be deleted, isn't it? how then i can operate it after calling a function?

fn main() {
    let vector = vec![1, 2, 3, 4, 5];

    let first_element = get_pointer_to_first_element(&vector);

    let vector: Vec<String> = Vec::new(); // Bonus question: "vector" variable is new now, so previous must be deleted?

    println!("first element is available and its {first_element}. ");
}

Vector: 0x5181aff7e8, and func result: 0x17e5bad99b0

I tried to use the same things with arrays, but result is the same.

  • Please only ask one question per Stack Overflow Question, but to 1 and 3 why do you expet the new vector and the old one to have the same addresses? The first and second `vector` are completely different variables the second one [shadows](https://stackoverflow.com/questions/53235334/in-rust-whats-the-difference-between-shadowing-and-mutability) the first. The old variable doesn't go out of scope just because it's no longer directly accessible so references stay valid. – cafce25 Feb 04 '23 at 13:23
  • 2 is just you taking the reference to the reference, try `first_element` instead of `&first_element` in the `println`. – cafce25 Feb 04 '23 at 13:28
  • @cafce25 Oh, forgot about creating a new vector in first example. But now i tried to remove it and the result is the same. – NekkiNekkiNekki Feb 04 '23 at 13:41

1 Answers1

3

In order:

  1. You allocated a new vector, so of course it'll have a different address. first_element points to the original vector. It was initialized with that value and it'll keep it. Even if you had not, your function takes a slice as an argument; not a Vec. Those are different types. The Vec is itself a pointer. The slice is a separate reference to, as the name suggests, a slice of the data on the heap it points to.
fn main() {
    let vector = vec![1, 2, 3];

    println!(
        "Normal: {:p}. Calculated /w a function: {:p}. Slice: {:p}.",
        &vector,
        get_vec_address(&vector),
        get_slice_address(&vector)
    );

    // This outputs:
    // Normal: 0x7fff91db1550. Calculated /w a function: 0x7fff91db1550. Slice: 0x55ddbc54a9d0.
}

fn get_vec_address(vec: &Vec<i32>) -> &Vec<i32> {
    vec
}

/// `&vector` is coerced from `&Vec` into `&[i32]`.
/// To learn more about Deref coercions, go to:
/// https://doc.rust-lang.org/book/ch15-02-deref.html#implicit-deref-coercions-with-functions-and-methods
fn get_slice_address(slice: &[i32]) -> &[i32] {
    slice
}

Run this snippet on Rust Playground. See this cheat sheet on containers for a visual explanation.

  1. As the comment says, you're taking the reference of a reference.
  2. pointer isn't dropped. It's moved as the return value. To get a better understanding of scope, you might want to review the chapters on scope and lifetimes.

As for your bonus question, shadowing a variable doesn't drop it. It'll still live to the end of the scope. If there are existing references to it, it can still be used. For example, this is valid code:

fn main() {
    let vector = vec![1, 2, 3];
    let first_element = &vector[0];
    let vector = vec![4, 5, 6];
    
    println!("{first_element}");
    println!("{vector:?}");

    // This will print:
    // 1
    // [4, 5, 6]
}

Run this snippet on Rust Playground.

verified_tinker
  • 625
  • 5
  • 17
  • Yeah, first one was my bad, because i tried different thing to figure out what happening and i made a mistake. But as i said in a comment, i tried to remove alocating a new vector and the pointers still point to different addresses. Second one is my bad too, tried it without & and it worked, thanks! And yeah, i will read about lifetimes, thanks a lot about it too. – NekkiNekkiNekki Feb 04 '23 at 13:46
  • @NekkiNekkiNekki That's because you're comparing the address of the `Vec`—itself a stack pointer—and the `slice` it points to. See the updated answer for an explanation. – verified_tinker Feb 04 '23 at 13:53
  • Oh, now i get it! Thanks again for that detailed response. I cant upvote you because low karma but keep it in mind, haha – NekkiNekkiNekki Feb 04 '23 at 13:58