C++指针解读(5)-- 指针和数组(多维数组)

news2024/11/26 10:43:50

相比一维数组,二维数组的概念和相关运算要复杂得多。

1、二维数组的存储及访问

假设有这么一个二维数组:

int arr[3][4] =
{
    { 10, 11, 12, 13 },
    { 20, 21, 22, 23 },
    { 30, 31, 32, 33 } 
};

我们可以把二维数组看成数组的数组:

(1)包含3行:arr[0]、arr[1]、arr[2];

(2)其中每一行是一个1维数组,它包含4个元素。

这里,我们用arr[0]表示第一行的一维数组;用arr[1] 表示第二行的一维数组;用arr[2] 表示第三行的一维数组。

因为在一维数组中,数组名代表首元素地址,所以arr[0]也表示一维数组arr[0]的首地址,即&arr[0][0];

同理,arr[1]表示&arr[1][0],arr[2]表示&arr[2][0]。

一定要记住这个重要的概念:arr[0]表示第一行的一维数组,arr[1]表示一二行的一维数组。依此类推。

后面对二维数组的访问,都是从这个概念开始展开的。因为对二维数组元素的访问,最终还是要转化到对一维数组的访问。

在一维数组中,指针+1就表示下一个数组元素的地址,所以arr[0]+1, arr[0]+2分别表示第2、第3个元素的地址。

现在我们用上面关于二维数组的知识来访问二维数组中的元素:

int main()
{
    int arr[3][4] =
    {
        { 10, 11, 12, 13 },
        { 20, 21, 22, 23 },
        { 30, 31, 32, 33 }
    };

    printf("%d  %d  %d  %d\n", *arr[0], *(arr[0] + 1), *(arr[0] + 2), *(arr[0] + 3));
    printf("%d  %d  %d  %d\n", *arr[1], *(arr[1] + 1), *(arr[1] + 2), *(arr[1] + 3));
    printf("%d  %d  %d  %d\n", *arr[2], *(arr[2] + 1), *(arr[2] + 2), *(arr[2] + 3));

    return 0;
}

现在我们可以总结下二维数组相关的指针

表示形式

含义

arr

二维数组名,二维数组元素首地址

arr[0], *arr

第0行的一维数组;也代表0行0列元素地址

arr[0] + 1, &arr[0][1]

0行1列元素地址

*arr[0]

0行0列元素的值,即10

*(arr[0] + 1)

0行1列元素的值,即11

2、二维数组的其他访问方式

前面我们讲到arr代表二维数组首元素的地址,因为这个二维数组由3个一维数组组成,所以arr也代表第一个一维数组的首地址。这样,arr+1就表示第二个一维数组的首地址。

我们可以用下面的代码来验证这个结论:

int main()
{
    int arr[3][4] =
    {
        { 10, 11, 12, 13 },
        { 20, 21, 22, 23 },
        { 30, 31, 32, 33 }
    };

    printf(" %p\n", arr);
    printf(" %p\n", arr + 1);
    int gap = (char)(arr + 1) - (char)(arr);
    printf(" %d\n", gap);

    return 0;
}

从输出结果看gap是16个字节,1个整型是4个字节,4个数组元素就是16个字节。arr + 1和arr刚好差一个一维数组所占空间的字节。

因为在一维数组中,arr[0]和*(a+0)等价,所以a[1]和*(a+1)等价,a[i]和*(a+i)等价。因此a[0]+1和*(a+0)+1都是&a[0][1]。

这里,再把二维数组相关指针再总结一下:

表示形式

含义

arr

二维数组名;二维数组元素首地址;表示一维数组arr[0]的首地址

arr[0], *arr, *(arr+0)

第0行的一维数组;也代表0行0列元素地址

arr[0] + 1, &arr[0][1], *(arr+0)+1

0行1列元素地址

*arr[0], *(*(arr+0))

0行0列元素的值

*(arr[0] + 1), *(*(arr+0)+1)

0行1列元素的值

arr[1]+2, *(arr+1)+2, &arr[1][2]

1行2列元素的值

二维数组在内存中是线性存储的,即按一维数组的方式存储,先存第1行,再存第2行。所以,我们可以按顺序方式访问二维数组。

int main()
{
    int arr[3][4] =
    {
        { 10, 11, 12, 13 },
        { 20, 21, 22, 23 },
        { 30, 31, 32, 33 }
    };

    printf(" *arr = %p  ,arr[0] = %p\n", *arr, arr[0]);
    int* p = *arr;
    for (int i = 0; i < 12; i++) {
        printf(" %d ", *(p + i));
    }

    return 0;
}

3、指向一维数组的指针

我们知道,指针变量必须包含它所指向的数据的类型信息,比如int *pi表示一个指向int型数据的指针变量。

arr, arr[0]虽然指向的地址相同,但它们俩所代表的含义是不一样的。

arr是第一个一维数组的首地址,所以arr+1就指向下一个一维数组的首地址,指针移动4*4 = 16个字节;而arr[0]是第一行第一列元素的地址,arr[0]+1下一个元素的指针,指针只移动4个字节。

怎么定义一个指向一维数组的指针?

int (*p)[4]

表示一个指向一维数组的指针,这个数组含4个元素。

注意,int (*p)[4]和int *p[4]的含义完全不同。int *p[4]表示一个数组,数组里的元素是int型指针变量。

用一维数组指针的访问二维数组:

int main()
{
    int arr[3][4] =
    {
        { 10, 11, 12, 13 },
        { 20, 21, 22, 23 },
        { 30, 31, 32, 33 }
    };
    int(*p)[4] = arr;

    for (int i = 0; i < 4; i++) {
        printf(" %d ", (*p)[i]);
    }

    printf("\n");
    for (int i = 0; i < 4; i++) {
        printf(" %d ", *((*p) + i));
    }

    return 0;
}

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

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

相关文章

Spring Cloud--Nacos+@RefreshScope实现配置的动态更新

原文网址&#xff1a;Spring Cloud--NacosRefreshScope实现配置的动态更新_IT利刃出鞘的博客-CSDN博客 简介 说明 本文介绍SpringCloud整合Nacos使用RefreshScope实现动态更新配置。 官网 Nacos Spring Cloud 快速开始 动态更新的介绍 动态更新的含义&#xff1a;修改应…

TOR(Top of Rack)

TOR TOR&#xff08;Top of Rack&#xff09;指的是在每个服务器机柜上部署1&#xff5e;2台交换机&#xff0c;服务器直接接入到本机柜的交换机上&#xff0c;实现服务器与交换机在机柜内的互联。虽然从字面上看&#xff0c;Top of Rack指的是“机柜顶部”&#xff0c;但实际T…

简述什么是值传递和引用传递?

1、什么是值传递,什么是引用传递? 值传递(pass by value)是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。 引用传递(pass by reference)是指在调用函数时将实际参数的地址直接传递到函数中,那么在函数中对参数…

位于同一子网下的ip在子网掩码配置错误的情况下如何进行通信(wireshrak抓包分析)

前言 最近看书发现个问题&#xff0c;正好想学习下wireshark的使用&#xff0c;于是抓包做了下实验。 问题是这样的&#xff0c;假设有服务器A和服务器B&#xff0c;正确配置下两者处于同一子网&#xff1b;此时B的网络配置正确&#xff0c;而A在配置子网掩码时出了错&#xff…

Linux寄存器+Linux2.6内核进程调度队列+命令行参数+环境变量

目录 一、寄存器 二、Linux2.6内核进程调度队列 &#xff08;一&#xff09;优先级 &#xff08;二&#xff09;活动队列 &#xff08;三&#xff09;过期队列 &#xff08;四&#xff09;active指针和expired指针 三、命令行参数 &#xff08;一&#xff09;举例一 &…

二分查找:如何用最省内存的方式实现快速查找功能?

文章来源于极客时间前google工程师−王争专栏。 有序数据集合的查找算法&#xff1a;二分查找(Binary Search)算法&#xff0c;也叫折半查找算法。二分查找的思想非常简单&#xff0c;但是难掌握好&#xff0c;灵活运用更加困难。 问题&#xff1a;假设有1000万个整数数据&…

用 Three.js 创建一个酷炫且真实的地球

接下来我会分步骤讲解&#xff0c;在线示例在数字孪生平台。 先添加一个球体 我们用threejs中的SphereGeometry来创建球体&#xff0c;给他贴一张地球纹理。 let earthGeo new THREE.SphereGeometry(10, 64, 64) let earthMat new THREE.MeshStandardMaterial({map: albed…

2023年建筑电工(建筑特殊工种)证考试题库及建筑电工(建筑特殊工种)试题解析

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2023年建筑电工(建筑特殊工种)证考试题库及建筑电工(建筑特殊工种)试题解析是安全生产模拟考试一点通结合&#xff08;安监局&#xff09;特种作业人员操作证考试大纲和&#xff08;质检局&#xff09;特种设备作业人…

搭建Umijs环境并创建一个项目 介绍基本操作

上文 Umijs介绍中 我们简单了解了一下这个东西 这里 我们还是不要关说不练了 直接终端执行 npm install -g umi可能会比较久 因为这个东西还挺大的 我们执行 umi -v这里就会输出版本 然后 我们创建一个文件夹目录 作为项目目录 然后 我们可以 通过 终端输入 mkdir 项目名称…

使用 Go 和 Wails 构建跨平台桌面应用程序

由于多种原因&#xff0c;Electron 曾经&#xff08;并且仍然&#xff09;大受欢迎。首先&#xff0c;其跨平台功能使开发人员能够从单个代码库支持 Linux、Windows 和 macOS。最重要的是&#xff0c;它对于熟悉 Javascript 的开发人员来说有一个精简的学习曲线。 尽管它有其缺…

LENOVO联想笔记本小新 Pro-14 2021AMD处理器ACH版(82MS)原厂Win10系统

下载链接&#xff1a;https://pan.baidu.com/s/1-KZ8Y9NmkS7nDXcMbhZLHw?pwdyrkx 系统自带所有驱动、出厂主题壁纸、系统属性专属LOGO标志、Office办公软件、lenovo联想电脑管家等预装程序 所需要工具&#xff1a;16G或以上的U盘 文件格式&#xff1a;ISO 文件大小&#xff1…

VScode运行C/C++

VScode运行C/C VScode的安装这里不讲 一、mingw64的下载 二、VS code打开文件夹与创建C文件 ----------------这一步给萌新看&#xff0c;有C和VScode的基础可跳过---------------- 1.创建一个文件夹 2.vscode打开刚刚创建的文件夹 3.新建文件&#xff0c;在输入文件名1.c后…

C语言中的文件操作指南

阅读导航 前言一、文件类型1. 程序文件2. 数据文件PS.文件名 二、文件的打开和关闭1. 文件指针2. 文件的打开和关闭 三、文件的顺序读写四、文件的随机读写1. fseek() 函数2. ftell() 函数3. rewind() 函数 总结 前言 在C语言中&#xff0c;文件操作是一项重要的任务。通过文件…

20和遍历以及迭代器有关的一些东西

知识点有点散&#xff0c;只能这样记录了 1、这边是和遍历有关的&#xff1a; class Person:def __init__(self):self.result 1def __getitem__(self, item):self.result 1if self.result > 6:raise StopIteration(停止遍历)return self.resultpassp Person() for i in…

Unity中Shader光照模型Phong的实现

文章目录 前言一、对主平行光实现高光效果1、在属性面板定义高光颜色2、在属性面板定义高光系数3、在属性面板定义高光范围系数4、获取 V (模型顶点的世界坐标 指到 相机世界坐标 的单位向量)5、由上一篇推理出的公式得到  R 向量6、由公式计算得出高光效果 二、使用已有的数…

常用的软件项目管理工具一览

软件项目管理工具是帮助团队成功管理和完成软件开发项目的软件程序和应用程序。根据项目及其规模和复杂性&#xff0c;可以使用各种各样的这些工具来协助完成任务&#xff0c;从任务跟踪和调度&#xff0c;到项目报告&#xff0c;到版本控制和协作。 项目经理对软件项目的整体成…

Git 回退代码的两种方法对比

Git 回退代码版本 在项目的开发中&#xff0c;有时候还是会出现&#xff0c;一些误提交了一些代码&#xff0c;这时候就会想撤回提交的代码&#xff0c;在Git中有两种方法可以使用&#xff0c;现在通过对比方法比较这两种方法的区别&#xff0c;分别适用于哪些情况&#xff1f…

Google zxing 生成带logo的二维码图片

环境准备 开发环境 JDK 1.8SpringBoot2.2.1Maven 3.2 开发工具 IntelliJ IDEAsmartGitNavicat15 添加maven配置 <dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.4.0</version> </…

Stm32_标准库_12_串口_发送数据

波特率&#xff1a;约定的传输速率&#xff0c;1000bps,1s发1000位 引脚 结构 数据帧的传输特点 代码&#xff1a; #include "stm32f10x.h" // Device header #include "Delay.h" #include "OLED.h"GPIO_InitTypeDef GPIO_InitStruct; USART…

计算机毕业设计选什么题目好?springboot 学习笔记系统

✍✍计算机编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java实战 |…