推广 热搜: csgo  vue  angelababy  2023  gps  新车  htc  落地  app  p2p 

Go by Example-图解数组

   2023-07-09 网络整理佚名1820
核心提示:3、声明数组时需要指定数据的类型,以及数组的长度。如果数组下标太大,编译会提示下标越界有时候,在一开始就想好了给数组赋几个值,赋什么值,这个时候我们可以使用下面的方式定义。了解了什么是指针了,下面让我们先看什么是数组指针。数组操作用图表示的话下面我们看看如果对指针数组进行复制操作,内存中变化什么样呢。通过图片可以得知,复制数组指针,只会复制指针的值,而不会复制指针所指向的值。

基本概念

1. 数组是一组具有相同唯一类型的编号且固定长度的数据项序列,可以是任何原始类型,例如整数、字符串或自定义类型。

2.在Go中,由于数组的内存布局是连续的,因此可以通过索引(位置)来读取(或修改)。 索引从0开始,第一个元素索引为0,第二个元素索引为1。以此类推。

3、声明数组时,需要指定数据类型和数组长度。

var array [6int
// 声明的规则:var + 变量名 + 类型

围棋则不同。 声明变量时,后面跟着“var”、变量名和变量类型。 在这里,我们声明了一个包含 6 个 int 类型元素的数组,该数组在初始化时将被设置为该类型的零值。

数组创建

声明一个长度为 5 的 int 类型的空数组。

    var arr=[5int {} 
    fmt.Println (arr)  

因为没有赋值,所以会打印它的零值,即5个零

上述过程可以用一个图来表示:

图中连续的五个蓝色格子表示数组占用的内存是连续分配的。

每个网格代表数组的一个元素,并且每个元素具有相同的类型。 这里的例子都是整数。 我们可以通过数组的下标来访问数组中对应位置的元素。

当数组初始化时,数组的每个元素都会被初始化为零值,在其他语言中称为默认值。

每种数据类型的零值也不同。 这里以我们的例子为例,因为每个元素都是int类型,所以它的零值为0。

声明一个长度为6的int类型数组并赋值

array:= [6int {5,1020304050}

如果忽略[]中的数字,并且没有设置数组的大小,Go语言会根据元素的个数设置数组的大小

arr1:=[...] int {1, 2, 3, 4, 5}  
fmt.Println (arr1)

需要注意的是,...是在不指定数组大小的情况下使用的。 如果你不写任何东西,它就是一个切片。

定义时也可以根据下标赋值

  array:=[5int {0:2,3:2

定义了一个长度为5的int类型数组,:前面的0和3代表当前下标,后面的是要赋值的值

从演示图中可以看出,下标为0和3的元素被赋值,其他未赋值的元素仍然为0。

如果数组下标太大,编译器会提示下标越界

array:=[4int {0:2,3:2
    array [6] =4 
    fmt.Println (array1)

这里我们定义数组的长度为4,最大下标为3。这是给下标的第六个元素赋值,编译失败。

数组复制

在Go中,相同类型、相同编号的数组可以直接互相赋值。

    // 复制
    array1:=[4int {0:2,3:2}
    array2:=[4int {}
    array3:=[4int {3,4,5,7}
    array2 =array1 // 具有相同类型的,相同个数的数组,可以相互直接进行赋值
    array3 =array2
    fmt.Println (array2)
    fmt.Println (array3) // 可以看到 array3 被 array2 完全覆盖

数组遍历

Go语言中特有的一个结构for...range,可以用来遍历数组的元素,也可以遍历map。先说数组

for ix, value := range array01 {
    ...
}

第一个返回值 ix 是数组的索引,第二个返回值是该索引处的值; 两者都是仅在 for 循环内部可见的局部变量。 value 只是索引位置处的值的副本,不能用于修改该索引位置处的值。如下例

package main
import "fmt"
var array [6int
func main () {
    array [1] =7 #根据下标给数组赋值,下标 0 开始。
    for k,v:=range array {
        fmt.Printf ("% d:% d \n",k,v)
    }
}

输出结果

0:0 
1:7
2:0 
3:0 
4:0 
5:0 

在上面的代码中,我们只为列表的第二个元素赋值。 可见其他位置的默认零值为0。

有时候,一开始我们就想过给数组赋几个值,赋什么值。 这时候我们就可以用下面的方法来定义。

然而,上面的代码有一个限制,一旦设置了长度,以后就可以更改。

因此,一般推荐使用下面文章中提到的切片。

数组指针和指针数组

在讲这个问题之前,首先需要了解一下什么是指针。

指针是一种变量,它不仅存储普通值(例如简单的整数或字符串),还存储另一个变量的内存地址。

指针变量可以指向任意值的内存地址。 它指向该值的内存地址。 它在32位机器上占用4个字节,在64位机器上占用8个字节,并且等于它指向的值的大小。 无关紧要。 当然,您可以声明指针指向任何类型的值以指示其原始性或结构; 可以在指针类型前面添加 * 号(前缀)来获取指针所指向的内容,其中 * 号是类型转换器。 使用指针来引用值称为间接寻址。

当定义指针但未将其分配给任何变量时,其零值为 nil。

每个变量在运行时都有一个地址,它代表该变量在内存中的位置。 在Go语言中,&运算符用于将变量放在变量前面,对变量进行“取址”操作。

知道了什么是指针,我们先来看看什么是数组指针。

简单来说,数组指针其实就是“数组指针”的缩写,即指针所指向的数组的内存地址。

其形式为

    var arr =  [...] int {5:2}
    // 数组指针
    var ptf *[6int = &arr // 和数组数量必须相等
    ptf [2]=3
    ptf [1]=7
    fmt.Println (ptf)

再看看指针数组,同样可以理解为指针数组的全称是“指针类型的数组”。

func main () {
    array1 := [5]*int {0new (int), 1new (int)}
    *array1 [0] = 10
    *array1 [1] = 20
    array1 [2] = new (int// 因为定义的时候没有给下标 2 的元素分配空间,所以这里是分配一块内存
    *array1 [2] = 30      // 如果没有上一步这步会报错
    fmt.Println (array1)
}

可以找到打印

[0xc000016038 0xc000016040]

所谓指针数组,就是数组的元素全部由指针组成。

如果将上面的数组运算用一个图来表示

此时数组中的每个元素实际上存储了一个指向new创建的对应类型的指针,这里是一个int类型的指针。

new的官方描述是:内置函数new用于分配内存,它的第一个参数是一个类型,而不是一个值,它的返回值是一个指向新分配的类型的零值的指针。

需要注意的一点是,只有在分配内存空间后才能操作元素。 如果元素为nil,直接给元素赋值就会出错,就像上面的[2]一样。

该数组的元素是指针类型,存储指向整数地址的指针。

指针数组的副本

让我们看看如果复制指针数组,内存中会发生什么。

func main () {
    array1 := [5]*int {0new (int), 1new (int)}

    // 为索引为 0 和 1 的元素赋值
    *array1 [0] = 10
    *array1 [1] = 20
    array2 := array1
    *array1 [0] =80
    fmt.Println (array2==array1)
}

从图中可以看出,复制数组指针只会复制指针的值,而不会复制指针指向的值。

因此,修改后的指针指向的地址也会相应改变,所以和相等。后记

在函数之间传递数组如果数组太大会造成巨大的开销,所以一般会转为指针。 这里为什么不单独解释是因为不建议将数组传递给函数。 相反,使用具有更高抽象级别的切片。

因为我也在学习,如果有不足的地方,欢迎大家指出。

 
反对 0举报 0 收藏 0 打赏 0评论 0
 
更多>同类资讯
推荐图文
推荐资讯
点击排行
网站首页  |  关于我们  |  联系方式  |  使用协议  |  版权隐私  |  网站地图  |  排名推广  |  广告服务  |  积分换礼  |  网站留言  |  RSS订阅  |  违规举报
Powered By DESTOON