如何理解Go语言的数组

news2024/11/27 16:40:32

什么是数组

首先下一个定义,数组是对线性的内存区域的抽象。高维数组和一维数组有着同样的内存布局。(大学生考试的时候别借鉴哈,这是自己下的定义,相当于是一篇议论文的论点。)

线性的内存区域说白了就是连续的内存区域。无论一维数组、二维数组、N维数组都处在连续的内存区域中,数据排列是连续的。CPU缓存对连续的内存区域具有较高的亲和性,这也是数组的访问速度要快于链表的一个重要原因。

一维数组

以C语言中的一维数组为例:int array[3] = {1,2,3};,此时array保存的即数组的首地址,以该地址为首的连续的内存区域中,保存了1,2,3的值。

二维数组

二维数组可以理解成:是保存了一维数组首地址(指针)一维数组
这是什么意思呢?以下面三个一维数组:array0array1array2为例,(前提,他们仨处于一块连续的内存区域上,且首尾无间断),假设它们的首地址分别是:0x00000x000C0x0018。看一下这三个数字,它们每两个之间的差都是0xc。因为C语言中int类型占4个字节宽度。所以说每个一维数组占用的内存长度都是12个字节,并且array1数组首地址刚好是array0数组末地址+1的位置,array2和array1的关系亦是如此。

int array0[3] = {1,2,3};
int array1[3] = {4,5,6};
int array2[3] = {7,8,9};

那么这片连续的内存区域可以表示为这个样子:

   +----++----++----++----++----++----++----++----++----+
...|  1 ||  2 ||  3 ||  4 ||  5 ||  6 ||  7 ||  8 ||  9 |...
   +----++----++----++----++----++----++----++----++----+
   ⬆                 ⬆                 ⬆
   0x0000            0x000c            0x0018
   array0            array1            array2

使用C语言定义一个一维指针数组:
int *array[3] = {array0,array1,array2};,数组中保存三个一维数组的首地址。

用该数组指针模拟一下二维数组。

#include "stdio.h"
int main() {
    int array0[3] = {1,2,3};
    int array1[3] = {4,5,6};
    int array2[3] = {7,8,9};
    int *array[3] = {array0,array1,array2};
    for(int i = 0; i < 3; i++) {
        for(int j = 0; j < 3; j++){
            printf("%d\t",*(*array+j)+i*3);
        }
        printf("\n");
    }
}

输出的内容是:

1       2       3
4       5       6
7       8       9

他的内存布局是这样的:

   +----++----++----++----++----++----++----++----++----+
...|  1 ||  2 ||  3 ||  4 ||  5 ||  6 ||  7 ||  8 ||  9 |...
   +----++----++----++----++----++----++----++----++----+
   ⬆                 ⬆                 ⬆
   0x0000            0x000c            0x0018
   array0            array1            array2
   
   +----------++----------++----------+
...|  0x0000  ||  0x000c  ||  0x0018  |...
   +----------++----------++----------+
   ⬆
   array

我们不搞的那么麻烦,直接用C语言定义一个普通的二维数组:

#include "stdio.h"
int main() {
    int array[3][3] =  {
            {1,2,3},
            {4,5,6},
            {7,8,9}};

    for(int i = 0; i < 3; i++) {
        for( int j = 0; j < 3; j++) {
            printf("%d\t",array[i][j]);
        }
        printf("\n");
    }
}

其打印内容也是:

1       2       3
4       5       6
7       8       9

使用访问连续内存区域的方式*((*array)+i),打印该数组:

#include "stdio.h"
int main() {
    int array[3][3] =  {
            {1,2,3},
            {4,5,6},
            {7,8,9}};
    
    for( int i = 0; i < 3 * 3; i++) {
        printf("%d\t",*((*array)+i));
    }
}

其输出内容为:

1       2       3       4       5       6       7       8       9

其内存布局是这样的:

   +----++----++----++----++----++----++----++----++----+
...|  1 ||  2 ||  3 ||  4 ||  5 ||  6 ||  7 ||  8 ||  9 |...
   +----++----++----++----++----++----++----++----++----+
   ⬆
   array
  • 可以看出,二维数组是将元素连续排列的一维数组。
  • 同理高维数组,也是将元素线性排列的一维数组。
  • 这也佐证了我们 数组是对线性的内存区域的抽象。高维数组和一维数组有着同样的内存布局 的观点。

如何理解Go语言的数组

Go语言中的数组,和C语言的数组大同小异,数组的首地址也指向了一片连续的内存区域。这里的数组指的是array,而不是slice

如何将一个一维数组映射成一个二维数组

仁者见仁,智者见智

第一种方式:

package main

import "fmt"

func main() {
	array0 := [12]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}
	var array [3][4]int
	for i := 0; i < 12; i++ {
		array[i/4][i%4] = array0[i]
	}
	fmt.Println(array)
}

上述方式展示了利用计算下标的方式进行转化,其结果为:

[[1 2 3 4] [5 6 7 8] [9 10 11 12]]

第二种方式,终极大杀器

在这里插入图片描述

package main

import (
	"fmt"
	"unsafe"
)

func main() {
	array0 := [12]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}
	var array = *(*[3][4]int)(unsafe.Pointer(&array0))
	fmt.Println(array)
}

结果为:

[[1 2 3 4] [5 6 7 8] [9 10 11 12]]

这种强制转化的方式,是利用了高维数组和一维数组有着同样的内存布局的这个原理,直接在类型层面做了一层转化,此时array 是 zero copy的,也就是说跟原数组共用同一片内存。二者只要更改任意一方元素,都会影响到对方。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1342366.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Spire.Office 8.12.2 for .NET

Spire.Office 8.12.2 发布。在此版本中&#xff0c;Spire.Doc支持Word到PCL和PostScript转换中的文本整形以及确定文档是否加密&#xff1b;Spire.Presentation支持将母版页转换为图像&#xff1b;Spire.PDFViewer支持在WinForm项目中使用Ctrl滚轮实现界面缩放效果。此外&#…

Python自动化测试:选择最佳的自动化测试框架

在开始学习python自动化测试之前&#xff0c;先了解目前市场上的自动化测试框架有哪些&#xff1f; 随着技术的不断迭代更新&#xff0c;优胜劣汰也同样发展下来。从一开始工具型自动化&#xff0c;到现在的框架型&#xff1b;从一开始的能用&#xff0c;到现在的不仅能用&…

Unity C# Mp3 Mp4 音频 视频 合成

需求 将声音文件合并到视频中 限制 暂时只支持Windows使用 准备 下载ffmpeg.exe 解压后得到exe https://ffmpeg.org/download.html#releases 注意事项&#xff1a; 目录要在一起 代码 public void StartExe(){if (File.Exists(ffmpegExe)){ string mp4;string mp3;//…

ERP与智能商品系统在供应链管理上有哪些区别和优势?

ERP系统和智能商品系统在供应链管理方面有以下区别和优势&#xff1a; 范围和综合性&#xff1a;ERP系统涵盖了企业的整个供应链管理过程&#xff0c;包括供应商管理、采购管理、库存管理、生产计划和物流管理等。它可以实现供应链上下游的信息共享和协同&#xff0c;提高供应…

活动快讯 | 万博智云受邀参加上海经信委,港澳办,香港贸发局主办的沪港主题活动

12月28日下午&#xff0c;上海市经信委、上海市人民政府港澳事务办公室、香港贸发局联合于上海城市数字化转型体验馆三楼会客厅举办沪港主题活动。万博智云CEO Michael受邀参加此次活动&#xff0c;探讨数字经济未来发展局势。 本次主题活动聚焦数据领域&#xff0c;邀请两地政…

echarts中给图表X轴和Y轴加单位以及给tooltip(提示框)增加单位

左边没有单位&#xff0c;右图是增加单位的效果。 1.x轴y轴设置单位 增加单位不管是x轴还是y轴都可以设置name字段&#xff0c;设置完name后效果是红色箭头效果。如果想要蓝色箭头效果可以使用x轴y轴的都有的 axisLabel 属性里面有formatter配置项&#xff0c;formatter支持字…

大数据前馈神经网络解密:深入理解人工智能的基石

文章目录 大数据前馈神经网络解密&#xff1a;深入理解人工智能的基石一、前馈神经网络概述什么是前馈神经网络前馈神经网络的工作原理应用场景及优缺点 二、前馈神经网络的基本结构输入层、隐藏层和输出层激活函数的选择与作用网络权重和偏置 三、前馈神经网络的训练方法损失函…

【qt】解决qt里编辑qss后失效问题(qt编码问题)

1、先创建qss文本stylesheet.qss 以按钮为例 QPushButton {background-color:rgb(240,255,255);color: rgb(0, 0, 2);border-style: outset;border-color: beige;border-radius: 10px; }/* hover按钮悬浮&#xff0c;鼠标悬浮在按钮上的状态&#xff0c;按钮颜色 */QPushButto…

CNAS中兴新支点——源代码审计对企业有哪些好处?

源代码扫描&#xff0c;对应用程序进行静态漏洞扫描&#xff0c;分析源代码中存在的安全风险&#xff0c;运行应用于模拟器中对应用进行实时漏洞攻击检测。 你是否了解源代码扫描对企业的好处&#xff1f; 一、源代码扫描&#xff0c;通常能够帮助企业解决这些问题&#xff1…

JS作用域链和闭包

JS作用域链和闭包 引题作用域链词法作用域闭包思考题 闭包如何回收 引题 有没有人跟我一样&#xff0c;面试中要是问基础&#xff0c;最怕遇到的就是闭包问题&#xff0c;闭包在 JavaScript 中几乎无处不在&#xff0c;理解作用域链是理解闭包的基础&#xff0c;同时作用域链和…

Baumer工业相机堡盟工业相机如何通过NEOAPI SDK获取相机当前实时帧率(C++)

Baumer工业相机堡盟工业相机如何通过NEOAPI SDK获取相机当前实时帧率&#xff08;C&#xff09; Baumer工业相机Baumer工业相机的帧率的技术背景Baumer工业相机的帧率获取方式CameraExplorer如何查看相机帧率信息在NEOAPI SDK里通过函数获取相机帧率&#xff08;C&#xff09; …

大创项目推荐 深度学习乳腺癌分类

文章目录 1 前言2 前言3 数据集3.1 良性样本3.2 病变样本 4 开发环境5 代码实现5.1 实现流程5.2 部分代码实现5.2.1 导入库5.2.2 图像加载5.2.3 标记5.2.4 分组5.2.5 构建模型训练 6 分析指标6.1 精度&#xff0c;召回率和F1度量6.2 混淆矩阵 7 结果和结论8 最后 1 前言 &…

什么是高并发系统?

1.1 什么是高并发&#xff1f; 高并发&#xff08;High Concurrency&#xff09;&#xff0c;通常是指通过设计保证系统能够同时处理很多请求。即在同一个时间点&#xff0c;有很多的请求同时访问同一个接口。高并发意味着大流量&#xff0c;需要运用技术手段去抵抗这种大流量…

行业智能终端定制

专注行业智能终端研发15年&#xff0c;有专业的技术和丰富的研发经验。产品定制范围&#xff1a;条码扫描手持机、RFID手持机、身份证手持机、行业平板、GPS/北斗高精度定位手持机/平板电脑、北斗短报文手持机。 能提供外观设计、结构设计、主板&#xff08;PCBA&#xff09;开…

JNPF开发平台--初体验

这一两年低代码的概念很流行&#xff0c;我也在网上了解体验了一番。 目前低代码主要分为两种&#xff0c;第一种是与云平台绑定的低代码&#xff0c;在云平台上开发&#xff0c;直接发布到云平台&#xff1b;第二种是低代码框架&#xff0c;低代码项目&#xff0c;这种比较流行…

mybatisX自动生成sql语句,尝试测试方法报错

今天我使用mybatisx自定义mapper方法生成sql语句后&#xff0c;在测试时报错 错误是MyBatis 无法找到映射的语句&#xff08;Statement&#xff09;引起的 我是这样操作的&#xff0c;在mapper接口自定义了一个方法 然后alt加enter&#xff0c;自动生成sql 结果 mapper.xml文件…

旅行旅游研学线路景点门票特产周边小程序开源版开发

旅行旅游研学线路景点门票特产周边小程序开源版开发 以下是旅行旅游研学线路景点门票特产周边小程序开源版开发的功能列表&#xff1a; 首页&#xff1a; 展示热门线路和推荐景点信息提供搜索功能&#xff0c;用户可以通过关键词搜索线路、景点、特产等显示当前位置和附近的景…

【Java干货教程】JSON,JSONObject,JSONArray类详解

一、定义 JSON&#xff1a;就是一种轻量级的数据交换格式&#xff0c;被广泛应用于WEB应用程序开发。JSON的简洁和清晰的层次结构&#xff0c;易于阅读和编写&#xff1b;同时也易于机器解析和生成&#xff0c;有效的提升网络传输效率&#xff1b;支持多种语言&#xff0c;很多…

主动红外探测器,预计到2026年将达到16 亿美元

主动红外探测器&#xff0c;也称为运动传感器&#xff0c;是一种通过发射红外辐射并检测反射来检测移动物体存在的电子设备。它们广泛用于安全系统、自动门、照明控制和其他需要运动检测的应用。近年来&#xff0c;由于对安全系统的需求不断增加以及智能家居和建筑的发展&#…

docker 安装可视化工具 Protainer 以及 汉化

一、创建保存数据的卷 安装网址&#xff1a;Install Portainer BE with Docker on Linux - Portainer Documentation docker pull portainer/portainer二、根据portainer镜像创建容器 docker run -d -p 8000:8000 -p 9000:9000\ --name portainer --restartalways \ -v /var/r…