使用指向数组的指针

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

Using a pointer to array

问题

我正在尝试使用谷歌的Go语言进行一些小的实验,但是我遇到了一个在C语言中相当基本的问题,但在我看到的文档中似乎没有涉及到。

当我将一个切片的指针传递给一个函数时,我以为我们可以通过以下方式访问它:

func conv(x []int, xlen int, h []int, hlen int, y *[]int)
    
    for i := 0; i<xlen; i++ {
        for j := 0; j<hlen; j++ {
            *y[i+j] += x[i]*h[j]
        }
    }
 }

但是Go编译器不喜欢这样:

sean@spray:~/dev$ 8g broke.go
broke.go:8: invalid operation: y[i + j] (index of type *[]int)

没错 - 这只是一个猜测。我有一个相当简单的解决方法:

func conv(x []int, xlen int, h []int, hlen int, y_ *[]int) {
    y := *y_

	for i := 0; i<xlen; i++ {
		for j := 0; j<hlen; j++ {
			y[i+j] += x[i]*h[j]
		}
	}
}

但肯定有更好的方法。令人恼火的是,在搜索Go的信息时,谷歌并不是很有用,因为大多数搜索结果都是关于C/C++/无关的。

英文:

I'm having a little play with google's Go language, and I've run into something which is fairly basic in C but doesn't seem to be covered in the documentation I've seen so far

When I pass a pointer to a slice to a function, I presumed we'd have some way to access it as follows:

func conv(x []int, xlen int, h []int, hlen int, y *[]int)
    
    for i := 0; i&lt;xlen; i++ {
        for j := 0; j&lt;hlen; j++ {
            *y[i+j] += x[i]*h[j]
        }
    }
 }

But the Go compiler doesn't like this:

sean@spray:~/dev$ 8g broke.go
broke.go:8: invalid operation: y[i + j] (index of type *[]int)

Fair enough - it was just a guess. I have got a fairly straightforward workaround:

func conv(x []int, xlen int, h []int, hlen int, y_ *[]int) {
    y := *y_

	for i := 0; i&lt;xlen; i++ {
		for j := 0; j&lt;hlen; j++ {
			y[i+j] += x[i]*h[j]
		}
	}
}

But surely there's a better way. The annoying thing is that googling for info on Go isn't very useful as all sorts of C/C++/unrelated results appear for most search terms.

答案1

得分: 34

谷歌Go文档关于传递数组的部分中提到,通常情况下你应该传递一个切片(而不是指针):

更新:

正如@Chickencha的评论所指出的,数组切片是引用类型,这就是为什么它们在传递时效率高的原因。因此,你可能会想要使用切片机制而不是“原始”指针。

来自谷歌Effective Go文档 http://golang.org/doc/effective_go.html#slices

切片是引用类型,


原文

它在标题关于类型的插曲下:

[...省略...] 当将一个数组传递给函数时,你几乎总是希望将形式参数声明为切片。当你调用函数时,取数组的地址,Go将会(高效地)创建一个切片引用并传递它。

编辑注:这不再适用

使用切片,你可以编写如下的函数(来自sum.go):

func sum(a []int) int {   // 返回一个int
    s := 0
    for i := 0; i < len(a); i++ {
        s += a[i]
    }
    return s
}

并像这样调用它:

s := sum(&[3]int{1,2,3})  // 将数组的切片传递给sum函数

也许可以将整个数组作为切片传递。谷歌指出Go对切片的处理效率很高。这是对问题的另一种答案,但也许是更好的方式。

英文:

The Google Go docs state the following about passing arrays - they say you usually want to pass a slice (instead of a pointer?):

Updated:

As indicated by @Chickencha's comment, array slices are references which is why they are efficient for passing. Therefore likely you will want to use the slice mechanism instead of "raw" pointers.

From Google Effective Go doc http://golang.org/doc/effective_go.html#slices
> Slices are reference types,


Original

It's under the heading

An Interlude about Types

> [...snip...] When passing an array
> to a function, you almost always want
> to declare the formal parameter to be
> a slice. When you call the function,
> take the address of the array and Go
> will create (efficiently) a slice
> reference and pass that.

Editor's note: This is no longer the case

Using slices one can write this function (from sum.go):

09    func sum(a []int) int {   // returns an int
10        s := 0
11        for i := 0; i &lt; len(a); i++ {
12            s += a[i]
13        }
14        return s
15    }

and invoke it like this:

19        s := sum(&amp;[3]int{1,2,3})  // a slice of the array is passed to sum    

Maybe pass the whole array as a slice instead. Google indicates Go deals efficiently with slices. This is an alternate answer to the question but maybe it's a better way.

答案2

得分: 21

类型为<code>[]int</code>这样的空<code>[]</code>的类型实际上是切片,而不是数组。在Go中,数组的大小是类型的一部分,所以要实际拥有一个数组,你需要有类似<code>[16]int</code>的东西,指向它的指针将是<code>*[16]int</code>。所以,你实际上已经在使用切片,切片的指针<code>*[]int</code>是不必要的,因为切片已经是按引用传递的。

<del>还要记住,你可以轻松地通过<code>&array</code>传递一个引用整个数组的切片(只要切片的元素类型与数组的元素类型匹配)。</del>(不再适用。)

示例:

package main
import "fmt"

func sumPointerToArray(a *[8]int) (sum int) {
    for _, value := range *a { sum += value }
    return
}
func sumSlice (a []int) (sum int) {
    for _, value := range a { sum += value }
    return
}
func main() {
    array := [...]int{ 1, 2, 3, 4, 5, 6, 7, 8 }
    slice := []int{ 1, 2, 3, 4 }
    fmt.Printf("通过指针求和数组:%d\n", sumPointerToArray(&array))
    fmt.Printf("求和切片:%d\n", sumSlice(slice))
    slice = array[0:]
    fmt.Printf("将数组作为切片求和:%d\n", sumSlice(slice))
}

编辑:根据Go的变化进行了更新,因为这是最初发布的。

英文:

Types with empty <code>[]</code>, such as <code>[]int</code> are actually slices, not arrays. In Go, the size of an array is part of the type, so to actually have an array you would need to have something like <code>[16]int</code>, and the pointer to that would be <code>*[16]int</code>. So, what you are actually doing already is using slices, and the pointer to a slice, <code>*[]int</code>, is unnecessary as slices are already passed by reference.

<del>Also remember that you can easily pass a slice referring to the entire array with <code>&array</code> (as long as the element type of the slice matches that of the array).</del> (Not anymore.)

Example:

package main
import &quot;fmt&quot;

func sumPointerToArray(a *[8]int) (sum int) {
    for _, value := range *a { sum += value }
    return
}
func sumSlice (a []int) (sum int) {
    for _, value := range a { sum += value }
    return
}
func main() {
    array := [...]int{ 1, 2, 3, 4, 5, 6, 7, 8 }
    slice := []int{ 1, 2, 3, 4 }
    fmt.Printf(&quot;sum arrray via pointer: %d\n&quot;, sumPointerToArray(&amp;array))
    fmt.Printf(&quot;sum slice: %d\n&quot;, sumSlice(slice))
    slice = array[0:]
    fmt.Printf(&quot;sum array as slice: %d\n&quot;, sumSlice(slice))
}

Edit: Updated to reflect changes in Go since this was first posted.

答案3

得分: 5

分号和星号被添加和移除。
> *y[i+j] += x[i]*h[j]

被解释为

> (*y)[i+j] += x[i] * h[j];

编辑: 请阅读评论。答案可能不再有效。我已经有一段时间没有接触过Go语言了,甚至无法再读懂这段代码。

英文:

The semicolon and the asterisk are added and removed.
> *y[i+j] += x[i]*h[j]

Is interpreted as

> (*y)[i+j] += x[i] * h[j];

EDIT: Please read the comments. The answer is probably no longer valid. and I haven't touched up on go for quite some time and can't even read this anymore.

答案4

得分: 2

长度是数组类型的一部分,您可以通过len()内置函数获取数组的长度。因此,您不需要传递xlen和hlen参数。

在Go中,当将数组传递给函数时,几乎总是可以使用切片。在这种情况下,您不需要使用指针。
实际上,您不需要传递y参数。这是C的输出数组的方式。

按照Go的风格:

func conv(x, h []int) []int {
    y := make([]int, len(x)+len(h))
    for i, v := range x { 
        for j, u := range h { 
            y[i+j] = v * u 
        }   
    }   
    return y
}

调用该函数:

conv(x[0:], h[0:])
英文:

The length is part of the array's type, you can get length of an array by the len() built-in function. So you needn't pass the xlen, hlen arguments.

In Go, you can almost always use slice when passing array to a function. In this case, you don't need pointers.
Actually, you need not pass the y argument. It's the C's way to output array.

In Go style:

func conv(x, h []int) []int {
    y := make([]int, len(x)+len(h))
    for i, v := range x { 
        for j, u := range h { 
            y[i+j] = v * u 
        }   
    }   
    return y
}

Call the function:

conv(x[0:], h[0:])

答案5

得分: 2

这是一个可工作的Go程序。

package main

import "fmt"

func conv(x, h []int) []int {
    y := make([]int, len(x)+len(h)-1)
    for i := 0; i < len(x); i++ {
        for j := 0; j < len(h); j++ {
            y[i+j] += x[i] * h[j]
        }
    }
    return y
}

func main() {
    x := []int{1, 2}
    h := []int{7, 8, 9}
    y := conv(x, h)
    fmt.Println(len(y), y)
}

为了避免猜测错误,请阅读Go文档:Go编程语言。

英文:

Here's a working Go program.

package main

import &quot;fmt&quot;

func conv(x, h []int) []int {
	y := make([]int, len(x)+len(h)-1)
	for i := 0; i &lt; len(x); i++ {
		for j := 0; j &lt; len(h); j++ {
			y[i+j] += x[i] * h[j]
		}
	}
	return y
}

func main() {
	x := []int{1, 2}
	h := []int{7, 8, 9}
	y := conv(x, h)
	fmt.Println(len(y), y)
}

To avoid wrong guesses, read the Go documentation: The Go Programming Language.

答案6

得分: 0

几乎所有其他回答这个问题的答案都谈到了使用切片而不是数组指针,但没有回答如何解决错误,所以我想写下这个答案。错误给了我们一个提示,它无法访问y的索引,因为这是一个无效的操作。

你的第一种方法是错误的,因为Go编译器会对你大喊大叫。第一种方法的问题在于*y[i+j]是错误的语法。这是因为从技术上讲,你正在做这个*(y[i+j]),你不能这样做,因为在你的情况下,y是一个指向int数组的指针。如果你打印y,它会打印数组的内存地址。

你试图获取y的第i+j个索引,但这个索引并不存在,因为y不是一个数组。你可以通过在语句中添加括号来修复你的代码,这将表明你正在尝试获取y指向的数组的第i+j个索引。使用(*y)[i+j]代替*y[i+j]。在进行这些更改后,函数将如下所示:

func conv(x []int, xlen int, h []int, hlen int, y *[]int) {
    for i := 0; i&lt;xlen; i++ {
        for j := 0; j&lt;hlen; j++ {
            (*y)[i+j] += x[i]*h[j]
        }
    }
}
英文:

Almost all the other answers to this question talk about using slices instead of
array pointers but none answers how to solve the error, so I thought I would
write this answer. The error gives us a hint that it cannot access the index of
y because it is an invalid operation.

Your first approach is wrong as the Go compiler shouts at you. The problem in
the first approach is that *y[i+j] is wrong syntax. This is because
technically you are doing this *(y[i+j]) and you can't just do that because
y in your case is a pointer to an int array. If you print y it would print
the memory address of the array.

You are trying to get the i+jth index of y which does not simply exist
because y is not an array. You can fix your code by adding parentheses to the
statement which would indicate that you are trying to get the i+jth index of
the array that y is pointing to. Use (*y)[i+j] instead of *y[i+j]. The
function would look like this after making the changes:

func conv(x []int, xlen int, h []int, hlen int, y *[]int) {
    for i := 0; i&lt;xlen; i++ {
        for j := 0; j&lt;hlen; j++ {
            (*y)[i+j] += x[i]*h[j]
        }
    }
}

huangapple
  • 本文由 发表于 2010年3月14日 02:24:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/2439453.html
匿名

发表评论

匿名网友

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

确定