如何理解Go语言的数组

什么是数组

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

线性的内存区域说白了就是连续的内存区域。无论一维数组、二维数组、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的,也就是说跟原数组共用同一片内存。二者只要更改任意一方元素,都会影响到对方。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

DDC和PLC的区别

前言 PLC与DDC控制器的比较&#xff0c;一直以来在相关领域内受到广泛关注。每个人站在不同的角度分析&#xff0c;都会有不同的结论&#xff0c;我们今天聊聊这个话题。 基本定义和功能 可编程控制器PLC与直接数字控制器DDC&#xff0c;两者都由CPU模块、I/O模块、显示模块…

中间件系列 - Redis入门到实战(高级篇-分布式缓存)

前言 学习视频&#xff1a; 黑马程序员Redis入门到实战教程&#xff0c;深度透析redis底层原理redis分布式锁企业解决方案黑马点评实战项目 中间件系列 - Redis入门到实战 本内容仅用于个人学习笔记&#xff0c;如有侵扰&#xff0c;联系删除 学习目标 Redis持久化Redis主从…

音画欣赏|《河水不犯井水的游戏》

《河水不犯井水的游戏》 尺寸&#xff1a;130x90cm 陈可之2007年绘 《警示贤文》之人和篇 天时不如地利&#xff0c;地利不如人和。 黄金未为贵&#xff0c;安乐值钱多。 钱财如粪土&#xff0c;仁义值千斤。 两人一般心&#xff0c;有钱堪买金。 一人一般心&#xff0c;无…

Ubuntu16.04 安装Anaconda

步骤 1&#xff1a; 去官网下载安装包,链接如下: https://repo.anaconda.com/archive/ 找到对应版本下载至本地电脑&#xff0c;并上传至服务器。 步骤2: 通过命令解压 sh Anaconda3-2023.03-0-Linux-x86_64.sh 一路选择yes或则回车&#xff0c;直到安装成功出现下面画面&…

本地部署Python Flask并搭建web问答应用程序框架实现远程访问

文章目录 前言1. 安装部署Flask并制作SayHello问答界面2. 安装Cpolar内网穿透3. 配置Flask的问答界面公网访问地址4. 公网远程访问Flask的问答界面 前言 Flask是一个Python编写的Web微框架&#xff0c;让我们可以使用Python语言快速实现一个网站或Web服务&#xff0c;本期教程…

Spring漏洞合集

目录 什么是spring区分Spring与Struts2框架的几种新方法CVE-2016-4977&#xff1a;Spring Security OAuth2 远程命令执行漏洞漏洞介绍 & 环境准备漏洞发现漏洞验证 & 利用1利用2 CVE-2017-4971&#xff1a;Pivotal Spring Web Flow 远程代码执行漏洞漏洞介绍 & 环境…

实习知识整理12:点击购物车渲染出购物车中的商品并实现在购物车界面对商品价格和数量的相关操作

1. 点击购物车渲染出购物车商品界面 通过userId从购物车表中查找商品的相关信息 前端&#xff1a;需要向后端传递userId 后端&#xff1a; CartMapper.java CartMapper.xml CartService.java 接口 CartServiceImpl.java 实现类 CartController.java cartIndex.html页面 …

php 8.4 xdebug扩展编译安装方法

最新版php8.4 xdebug扩展只能通过编译方式安装, pecl是安装不了的, 编译方法如下 下载最新版xdebug git clone https://github.com/xdebug/xdebug.git 却换入xdebug目录执行编译安装xdebug cd xdebug phpize./configure --enable-xdebugmakemake install3. 配置启用xdebug 这…

关于java选择结构if和else详解

关于java选择结构if和else详解 在上篇文章中我们了解了java的基本流程控制之一用户交互&#xff0c;也讲述了scanner类的使用方式&#xff0c;本篇文章中我们来深入一下下一个java流程控制&#xff0c;if和else&#xff0c;这个是非常关键的&#xff0c;也是我们以后的工作中最…

Java-File:遍历目录下的所有文件

一个常用file工具类&#xff0c;用来扫描给定目录下的所有文件&#xff0c;返回对应文件的全路径。 public static ArrayList<Object> scanFilesWithSubPackage(String path) {ArrayList<Object> scanFiles new ArrayList<Object>();LinkedList<File>…

40G多模光模块QSFP-40G-SR4优势及应用领域介绍

QSFP-40G-SR4光模块是一种常用的光纤传输解决方案。传输速率40G&#xff0c;SR代表短距离多模光纤&#xff08;Short Range Multimode Fiber&#xff09;&#xff0c;4表示有四个光纤通道。这种光模块采用MPO/MTP多模光纤连接器来实现高速传输&#xff0c;传输距离可以达到300米…

骨传导耳机的原理是什么?一文读懂骨传导耳机优缺点都有哪些!

一、骨传导耳机传声原理是什么 骨传导耳机以人体骨骼为传声介质&#xff0c;可以将声音转化为不同频率的震动&#xff0c;在不经过外耳道和鼓膜的情况下&#xff0c;通过震动使声音经过内耳道&#xff0c;直接传入大脑听觉神经&#xff0c;与传统耳机相比&#xff0c;可以节省许…

【堡垒机小问答】堡垒机最早起源于哪里?是国外吗?

随着大家网络安全意识的增加&#xff0c;对于堡垒机的了解也越来越多。最近有不少小伙伴在问&#xff0c;堡垒机最早起源于哪里&#xff1f;是国外吗&#xff1f;这里我们就来简单回答一下。 堡垒机最早起源于哪里&#xff1f;是国外吗&#xff1f; 【回答】&#xff1a;堡垒…

关于“Python”的核心知识点整理大全49

目录 16.2.10 加亮颜色主题 16.3 小结 第&#xff11;7 章 使用API 17.1 使用 Web API 17.1.1 Git 和 GitHub 17.1.2 使用 API 调用请求数据 17.1.3 安装 requests 17.1.4 处理 API 响应 python_repos.py 注意 17.1.5 处理响应字典 python_repos.py import json i…

We are a team - 华为OD统一考试

OD统一考试 题解&#xff1a; Java / Python / C 题目描述 总共有 n 个人在机房&#xff0c;每个人有一个标号 (1<标号<n) &#xff0c;他们分成了多个团队&#xff0c;需要你根据收到的 m 条消息判定指定的两个人是否在一个团队中&#xff0c;具体的: 消息构成为 a b …

HMS SQL注入(CVE-2022-25491)

漏洞描述&#xff1a; 2022年3月15日&#xff0c;CVE收录了编号CVE-2022-25491漏洞&#xff0c;该漏洞为在HMS v1.0版本中存在SQL注入漏洞&#xff0c;该漏洞允许攻击者通过手动调试appointment.php文件中的editid软件参数进行SQL注入攻击。 复现过程&#xff1a; 1.访问ip&…

深入理解Golang:切片的底层机制解析

深入理解Golang&#xff1a;切片的底层机制解析 引言切片的基本概念切片的内部结构内存管理机制切片与数组的对比切片的高级用法性能优化建议案例研究 引言 在现代软件开发中&#xff0c;高效的数据处理和优化的内存管理是每位开发者都需面对的挑战。特别是在使用像Go语言&…

部署一款开源的网站监控工具—Uptime Kuma

项目介绍 项目地址&#xff1a;louislam/uptime-kuma: A fancy self-hosted monitoring tool (github.com) Uptime Kuma是一个开源的网络服务监控工具。它允许用户监视他们的网络服务&#xff0c;以确保其正常运行&#xff0c;并提供有关服务可用性和性能的实时信息。Uptime K…

R503S指纹识别模块的指令系统(一)

1.采集指纹图像 GetImage&#xff08;0x01&#xff09; 功能说明&#xff1a;探测手指&#xff0c;探测到后录入指纹图像存于 ImageBuffer&#xff0c;并返回录入成功确认码&#xff1b;若探测不到手指&#xff0c;直接返回无手指确认码(模块对于每一条指令都快速反应&#xf…

Go 语言如何读取 excel 测试数据,简单易学

&#x1f4e2;专注于分享软件测试干货内容&#xff0c;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01;&#x1f4e2;交流讨论&#xff1a;欢迎加入我们一起学习&#xff01;&#x1f4e2;资源分享&#xff1a;耗时200小时精选的「软件测试」资…