Используя указатель на массив

У меня есть немного игры с языком Движения Google, и я столкнулся с чем-то, что является довольно основным в 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]
        }
    }
 }

Но компилятору Движения не нравится это:

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]
        }
    }
}

Но конечно существует лучший путь. Раздражающая вещь состоит в том, что поиск с помощью Google для получения информации о Движении не очень полезен, поскольку все виды результатов C/C ++/unrelated появляются для большинства критериев поиска.

32
задан Sean 2 August 2016 в 13:37
поделиться

5 ответов

Вот рабочая программа 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.

2
ответ дан 27 November 2019 в 20:47
поделиться

точка с запятой и звездочка добавляются и удаляются.

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

5
ответ дан 27 November 2019 в 20:47
поделиться

Длина является частью типа массива, вы можете получить длину массива с помощью встроенной функции 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:])
2
ответ дан 27 November 2019 в 20:47
поделиться

В документации Google Go говорится следующее о передаче массивов - они говорят, что вы обычно хотите передать срез ( вместо указателя?):

Обновлено:

Как указано в комментарии @ Chickencha, фрагменты массива являются ссылками, поэтому они эффективны для передачи.Поэтому, вероятно, вы захотите использовать механизм срезов вместо «сырых» указателей.

Из Документа Google Effective Go http://golang.org/doc/effective_go.html#slices

Срезы являются ссылочными типами,


Исходные

Под заголовком

Интерлюдия о типах

[... snip ...] При передаче массива функции, вы почти всегда хотите, чтобы объявлял формальный параметр как срез. Когда вы вызываете функцию, принимает адрес массива, а Go создает (эффективно) ссылку на фрагмент и передает ее.

Примечание редактора: это уже не тот случай.

Используя срезы, можно написать эту функцию (из sum.go):

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

и вызывать ее следующим образом:

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

Вместо этого можно передать весь массив как срез . Google указывает, что Go эффективно обрабатывает фрагменты. Это альтернативный ответ на вопрос, но, возможно, это лучший способ.

25
ответ дан 27 November 2019 в 20:47
поделиться

Типы с пустыми [], например [] int , на самом деле являются срезами, а не массивами. В Go размер массива является частью типа, поэтому, чтобы на самом деле иметь массив, вам нужно иметь что-то вроде [16] int , а указатель на это будет * [16] int . Итак, то, что вы на самом деле уже делаете, - это использование срезов, и указатель на срез, * [] int , не нужен, поскольку срезы уже переданы по ссылке.

Также помните, что вы можете легко передать фрагмент, относящийся ко всему массиву, с помощью & array (при условии, что тип элемента фрагмента совпадает с типом элемента массива). (Больше нет.)

Пример:

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("sum arrray via pointer: %d\n", sumPointerToArray(&array))
    fmt.Printf("sum slice: %d\n", sumSlice(slice))
    slice = array[0:]
    fmt.Printf("sum array as slice: %d\n", sumSlice(slice))
}

Редактировать : Обновлено, чтобы отразить изменения в Go с момента его первой публикации.

17
ответ дан 27 November 2019 в 20:47
поделиться
Другие вопросы по тегам:

Похожие вопросы: