0

リンクされたリストを実装しているときに、生のポインターを学習するのに苦労しています。単純なコードで意図しない結果が得られ、その説明を見つけるのに苦労しています。

use std::cmp::PartialEq;
use std::default::Default;
use std::ptr;

pub struct LinkedListElement<T> {
    pub data: T,
    pub next: *mut LinkedListElement<T>,
}

pub struct LinkedList<T> {
    head: *mut LinkedListElement<T>,
}

impl<T: PartialEq> LinkedListElement<T> {
    pub fn new(elem: T, next: Option<*mut LinkedListElement<T>>) -> LinkedListElement<T> {
        let mut_ptr = match next {
            Some(t) => t,
            None => ptr::null_mut(),
        };
        let new_elem = LinkedListElement {
            data: elem,
            next: mut_ptr,
        };
        if !mut_ptr.is_null() {
            println!(
                "post create ll mut ptr: {:p}, post create ll mut ptr next {:p}",
                mut_ptr,
                unsafe { (*mut_ptr).next }
            );
        }
        new_elem
    }
}

impl<T: PartialEq + Default> LinkedList<T> {
    pub fn new(elem: T) -> LinkedList<T> {
        LinkedList {
            head: &mut LinkedListElement::new(elem, None),
        }
    }

    pub fn insert(&mut self, elem: T) {
        println!("head: {:p} . next: {:p}", self.head, unsafe {
            (*self.head).next
        });
        let next = Some(self.head);
        let mut ll_elem = LinkedListElement::new(elem, next);
        println!(
            "before pointer head: {:p}. before pointer next {:p}",
            self.head,
            unsafe { (*self.head).next }
        );
        let ll_elem_ptr = &mut ll_elem as *mut LinkedListElement<T>;
        self.head = ll_elem_ptr;
    }
}

fn main() {
    let elem: i32 = 32;
    let second_elem: i32 = 64;
    let third_elem: i32 = 72;
    let mut list = LinkedList::new(elem);
    list.insert(second_elem);
    list.insert(third_elem);
}

(遊び場)

このコードにより、次の出力が得られます。

head: 0x7ffe163275e8 . next: 0x0
post create ll mut ptr: 0x7ffe163275e8, post create ll mut ptr next 0x0
before pointer head: 0x7ffe163275e8. before pointer next 0x0
head: 0x7ffe16327560 . next: 0x7ffe163275e8
post create ll mut ptr: 0x7ffe16327560, post create ll mut ptr next 0x7ffe163275e8
before pointer head: 0x7ffe16327560. before pointer next 0x7ffe16327560

最初の 2 つの要素では、コードは期待どおりに動作します。次の要素として null ポインターを持つ要素を作成します。2 番目の要素を追加した後の状態は次のとおりです。

{
  head: {
    elem: 64,
    next: {
      elem: 32,
      next: nullptr
    }
  }
}

64 -> 32 -> null

3 番目の要素が追加されると、事態はおかしくなり、リンクされたリストは次のように変換されます。

{
  head: {
    elem: 72,
    next: {
      elem: 72,
      next: {
        elem: 72,
        next: ...
      }
    }
  }
}

72 -> 72 -> 72 -> ...

リンクされたリスト要素のnextフィールドが要素自体を指し始めているようです。

メソッドをデバッグしたLinkedListElement::newところ、適切な要素が返されるはずであることがわかりました。

{
  elem: 72,
  next: {
    elem: 64,
    next: {
      elem: 32,
      next: nullptr
    }
  }
}

LinkedList::insertメソッドに戻された直後、self.head再代入前でもなぜか中身LinkedList selfが「壊れた」状態になってしまう。

Rust で生のポインターを使用することは慣用的ではないことはわかっていますが、それでも学びたいと思っています。

4

1 に答える 1