New to GO. Having invalid memory access related errors

huangapple go评论74阅读模式
英文:

New to GO. Having invalid memory access related errors

问题

在GO的世界中我是非常新手的,事实上这是我第一次编写GO程序。我正在编写一个反转链表的算法,具体来自于这个leetcode。下面的代码片段并没有透露我的算法,只是我用来测试实现的main()函数。调试后,我发现我在这里箭头处出错,错误信息是panic: runtime error: invalid memory address or nil pointer dereference

type ListNode struct {
	Val int
	Next *ListNode
}
func main(){
	var list *ListNode
	head := list
	for i := 0; i <= 5; i++ {
		var dummy *ListNode
		list.Val = i    <--------------------- 这里
		list.Next = dummy
		dummy = list
	}
	result := reverseList(head)

	for result != nil{
		fmt.Printf("%d\t", result.Val)
	}
}

我非常希望能对这个问题进行一些讨论!

英文:

extremely green in the world of GO - infact this is my first ever program in GO. I'm writing an algorithm that reverses a linked list, specifically from this leetcode. The code snippet below doesn't disclose my algorithm, only the main() function I'm using to test my implementation. After debugging, I found that I fail at the here arrow with the error message panic: runtime error: invalid memory address or nil pointer dereference.

type ListNode struct {
	Val int
	Next *ListNode
}
func main(){
	var list *ListNode
	head := list
	for i := 0; i &lt;= 5; i++ {
		var dummy *ListNode
		list.Val = i    &lt;--------------------- here
		list.Next = dummy
		dummy = list
	}
	result := reverseList(head)

	for result != nil{
		fmt.Printf(&quot;%d\t&quot;, result.Val)
	}
}

I would really appreciate some discussion to this problem!

答案1

得分: 2

基本问题是你从未为你的结构体指针分配内存。当你写下:

var list *ListNode

你创建了一个指向ListNode类型的指针,但实际上你并没有为它分配任何内存。所以当你尝试写入...

list.Val = i

你会得到"invalid memory address"错误,因为你试图解引用一个未定义的指针。一种分配内存的方法是使用new()内置函数:

var list *ListNode = new(ListNode)

你也可以像这样取结构体的地址:

list := &ListNode{}

上面显示了正确的语法,但如果你只是用上面的代码替换你现有的var声明,你的代码仍然会有逻辑问题:在将第一个节点添加到列表之前,你不想分配任何内存。这意味着我们要等到在for循环内部分配内存。

对你的代码进行一些小的修改,我们得到:

package main

import "fmt"

type ListNode struct {
    Val  int
    Next *ListNode
}

func main() {
    var head, tail *ListNode

    for i := 0; i <= 5; i++ {
        node := new(ListNode)
        node.Val = i

        if tail == nil {
            // 这是列表中的第一个节点,所以只需将head和tail指向新节点。
            tail = node
            head = tail
        } else {
            // 列表中至少有一个节点,所以将新节点连接到尾部
            tail.Next = node
            tail = node
        }
    }

    result := head

    for result != nil {
        fmt.Printf("%d\t", result.Val)

        // 不要忘记增加到下一个节点!
        result = result.Next
    }
}

运行这段代码会产生:

0       1       2       3       4       5
英文:

The basic problem is that you're never allocating memory for your struct pointers. When you write:

var list *ListNode

You have created a pointer-to-ListNode type, but you haven't actually allocated any memory for it. So when you try to write...

list.Val = i

You get the "invalid memory address" error, because you're trying to dereference an undefined pointer. One way of allocating memory is to use the new() new builtin function:

var list *ListNode = new(ListNode)

You can also take the address of a struct, like this:

list := &amp;ListNode{}

The above shows the correct syntax, but if you were to simply replace
your existing var declaration with the above you would still have
logic problems in your code: you don't want to allocate any memory
until you add the first node to the list. That means we want to wait
until we're inside the for loop to allocate memory.

With some minor changes to your code, we get:

package main

import &quot;fmt&quot;

type ListNode struct {
    Val  int
    Next *ListNode
}

func main() {
    var head, tail *ListNode

    for i := 0; i &lt;= 5; i++ {
        node := new(ListNode)
        node.Val = i

        if tail == nil {
            // This is the first node in the list, so just point head
            // and tail at the new node.
            tail = node
            head = tail
        } else {
            // There is at least one node in the list, so attach the new
            // node to the tail
            tail.Next = node
            tail = node
        }
    }

    result := head

    for result != nil {
        fmt.Printf(&quot;%d\t&quot;, result.Val)

        // Don&#39;t forget to increment to the next node!
        result = result.Next
    }
}

Running this code produces:

0       1       2       3       4       5

答案2

得分: 2

你必须为列表节点分配内存。当创建列表节点时,要么更新前一个节点的Next字段,要么更新列表头(如果这是第一个节点)。

var head *ListNode

// p是指向头部或前一个节点的Next的指针。
// 我们从将p设置为指向头部开始。
p := &head

for i := 0; i <= 5; i++ {
	// 分配一个具有初始化值的新ListNode。
	n := &ListNode{Val: i}

	// 更新头部或前一个节点的Next字段。
	*p = n

	// 循环的下一次迭代应该更新我们刚刚创建的节点的Next字段。
	p = &n.Next
}

// 当列表节点不为nil时循环。
for n := head; n != nil; n = n.Next {
	fmt.Println(n.Val)
}

https://go.dev/play/p/qUhza05kUFT

英文:

You must allocate memory for the list nodes. As the list nodes are created, either update the Next field in the previous node or the list head if this is the first node.

var head *ListNode

// p is pointer to head or pointer to previous node&#39;s Next.  
// We start with p set as pointer to the head.
p := &amp;head

for i := 0; i &lt;= 5; i++ {
	// Allocate a new ListNode with Val initialized.
	n := &amp;ListNode{Val: i}

	// Update head or previous node&#39;a Next field.
	*p = n

	// The next iteration of the loop should update
	// the Next field in the node that we just created.
	p = &amp;n.Next
}

// Loop while list node is not nil.
for n := head; n != nil; n = n.Next {
	fmt.Println(n.Val)
}

https://go.dev/play/p/qUhza05kUFT

huangapple
  • 本文由 发表于 2022年5月25日 06:56:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/72370283.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定