基本概念

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

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

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

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

Go 和 Python 不一样,在声明变量的时候依次是 “var”、变量名、变量类型。这里我们声明一个包含 6 个元素的 int 类型的数组,这个数组在初始化的时候会被设置为该类型的零值。

数组创建

  1. 声明一个长度为 5 的 int 类型的空数组。
	var arr=[5] int {}
fmt.Println (arr)

因为没有赋值,所以会打印其零值也就是 5 个 0

上面的过程我们可以通过一个图来表示:



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

每一个格子表示数组的一个元素,每个元素的类型相同,这里的例子全是整数的,我们可以通过数组的下标访问数组中对应位置的元素。

当数组初始化的时候,数组每个元素都会初始化为其零值,其他语言习惯叫默认值。

每个数据类型的零值也是不一样的,这里就拿我们这个例子,因为每个元素都是 int 类型所以其零值为 0。

  1. 声明一个长度为 6 的 int 类型数组并赋值
array:= [6] int {5,10, 20, 30, 40, 50}
  1. 如果忽略 [] 中的数字不设置数组大小,Go 语言会根据元素的个数来设置数组的大小
arr1:=[...] int {1, 2, 3, 4, 5}
fmt.Println (arr1)

需要注意不指定数组大小的时候使用 ..., 如果不写东西就是切片了。

4. 还可以在定义的时候根据下标进行赋值

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

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



通过演示图可以得知,下标 0 和 3 的元素赋值了,其他没有赋值的元素仍然是 0。

  1. 如果数组下标太大,编译会提示下标越界
array:=[4] int {0:2,3:2}
array [6] =4
fmt.Println (array1)

这里我们定义了数组长度为 4,其下标最大是 3, 这是要给下标第 6 个元素赋值,编译不通过。

数组复制

在 Go 中具有相同类型的,相同个数的数组,可以相互直接进行赋值。

	// 复制
array1:=[4] int {0:2,3:2}
array2:=[4] int {}
array3:=[4] int {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 只是 array01 某个索引位置的值的一个拷贝,不能用来修改 array01 该索引位置的值。如下面的例子

package main
import "fmt"
var array [6] int
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 *[6] int = &arr // 和数组数量必须相等
ptf [2]=3
ptf [1]=7
fmt.Println (ptf)

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

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

打印可以发现

[0xc000016038 0xc000016040]

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

上面 array1 数组操作用图表示的话



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

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

需要注意的一点是只有给元素分配内存空间了才能对其进行操作,如果元素是 nil,直接对元素赋值的话就会出现错误,就像上面的 array1[2]。

这个数组的元素是指针类型的,存放的是指向整数的地址的指针。

指针数组的复制

下面我们看看如果对指针数组进行复制操作,内存中变化什么样呢。

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



通过图片可以得知,复制数组指针,只会复制指针的值,而不会复制指针所指向的值。

所以修改 array1 的指针指向的地址时,array2 也会跟着变,所以 array1 和 array2 相等。

后记

在函数间传递数组,如果数组过大将造成巨大的开销,所以一般会将其转换为指针,这里为什么没有单独的拿出讲解,就是因为不推荐给函数传入数组。而是使用抽象度更高的切片。

更多内容关注公众号:python学习开发,添加微信:italocxa,回复加群:关键词Python、Go,需要哪个回复哪个即可。

Go by Example-图解数组的更多相关文章

  1. Java - 数组详解(图解数组的基本操作)

    目录 什么是数组 数组的定义和内存分配 数组的赋值和访问 数组的注意事项 数组的内存图解 数组的插入 数组的删除 数组的扩容 数组的反转 首先 什么是数组 数组是一组地址连续.长度固定的具有相同类型的 ...

  2. 05 方法与数组笔记【JAVA】

    ---恢复内容开始--- 1:方法(掌握) (1)方法:就是完成特定功能的代码块. 注意:在很多语言里面有函数的定义,而在Java中,函数被称为方法. (2)格式: 修饰符 返回值类型 方法名(参数类 ...

  3. Java Day 04

    01 语句 循环结构 嵌套  列的递减 1-5 2-5 3-5// 1-5 1-4 1-3 转义字符 \n 回车 \t 制表符 \b 退格 \r 按下回车键 windows 回车符由 \r \n 组成 ...

  4. Junit 注解 类加载器 .动态代理 jdbc 连接池 DButils 事务 Arraylist Linklist hashset 异常 哈希表的数据结构,存储过程 Map Object String Stringbufere File类 文件过滤器_原理分析 flush方法和close方法 序列号冲突问题

    Junit 注解 3).其它注意事项: 1).@Test运行的方法,不能有形参: 2).@Test运行的方法,不能有返回值: 3).@Test运行的方法,不能是静态方法: 4).在一个类中,可以同时定 ...

  5. JavaBasic_05

    方法 简述:实现特定功能的代码块 格式 修饰符: 返回值类型 方法名(参数类型 参数名1,参数类型 参数名2…){           函数体;           return 返回值;} 方法格式 ...

  6. 字符串模式匹配之KMP算法图解与 next 数组原理和实现方案

    之前说到,朴素的匹配,每趟比较,都要回溯主串的指针,费事.则 KMP 就是对朴素匹配的一种改进.正好复习一下. KMP 算法其改进思想在于: 每当一趟匹配过程中出现字符比较不相等时,不需要回溯主串的 ...

  7. js数组操作-最佳图解

    js数组操作-最佳图解

  8. 06-01 Java 二维数组格式、二维数组内存图解、二维数组操作

    二维数组格式1 /* 二维数组:就是元素为一维数组的一个数组. 格式1: 数据类型[][] 数组名 = new 数据类型[m][n]; m:表示这个二维数组有多少个一维数组. n:表示每一个一维数组的 ...

  9. Java中数组在内存中的图解

    Java中的数组在内存中的图解,其实对于数组,还是比较熟悉的,平时用的也是很多的,在看数据结构与算法的极客时间专栏,最常用的10个数据结构:数组.链表.栈.队列.散列表.二叉树.堆.跳表.图.Trie ...

  10. 图解c/c++多级指针与“多维”数组

    声明:本文为原创博文,如有转载,请注明出处.若本文有编辑错误.概念错误或者逻辑错误,请予以指正,谢谢. 指针与数组是C/C++编程中非常重要的元素,同时也是较难以理解的.其中,多级指针与“多维”数组更 ...

随机推荐

  1. js实现图片的Blob base64 ArrayBuffer 的各种转换

    一.相关基础知识 构造函数 FileReader() 返回一个新构造的FileReader 事件处理 FileReader.onabort  处理abort事件.该事件在读取操作被中断时触发. Fil ...

  2. FICO-Payment Terms 收付款条件和分期付款设置

    转载:https://www.cnblogs.com/weichuo/p/3524278.html Payment Terms 收付款条件和分期付款设置 SAP Payment Terms 中文翻译为 ...

  3. 【常用技巧】js开发的一些技巧

    1.console.log的特殊用法: 添加%c特殊符号即可打印出样式 console.log("%c djsakiasjdkasjdkjas","font-size:6 ...

  4. Linux命令——source

    参考:What does 'source' do? 前言 当我们修改了/etc/profile文件,并想让它立刻生效,而不用重新登录,就可以使用source命令,如source /etc/profil ...

  5. STM32定时器配置(TIM1、TIM2、TIM3、TIM4、TIM5、TIM8)高级定时器+普通定时器,定时计数模式下总结

    文章结构: ——> 一.定时器基本介绍 ——> 二.普通定时器详细介绍TIM2-TIM5 ——> 三.定时器代码实例 一.定时器基本介绍  之前有用过野火的学习板上面讲解很详细,所以 ...

  6. sql基本操作之增删改查

    1. 显示数据库 show databases; show databases; 2. 显示当前数据库 select current_database(); 3. 创建/删除数据库 create da ...

  7. Chkdsk /f 修复无法识别EXFAT卷文件系统

    Chkdsk 工具将错误地报告为损坏的 Windows 7 和 Windows Server 2008 R2 中 exFAT 卷文件系统 适用于: Windows Server 2008 R2 Ser ...

  8. rabbitmq数据备份与还原

    一.场景 现在有服务器A和服务器B ,由于业务需要,要求把服务器A上mq的数据迁移到服务器B上,rabbitmq的数据包括元数据(RabbitMQ用户.vhost.队列.交换和绑定)和消息数据,而消息 ...

  9. k8s的认证授权

    一.ServiceAccount Service account是为了方便Pod里面的进程调用Kubernetes API或其他外部服务而设计的.它与User account不同   User acc ...

  10. java中创建对象的方式

    Java中有5种创建对象的方式,下面给出它们的例子还有它们的字节码 使用new关键字 } → 调用了构造函数 使用Class类的newInstance方法 } → 调用了构造函数 使用Construc ...