二维数组与数组指针详解

article/2025/8/21 19:19:25

二维数组

深入理解二维数组

  • 首先定义一个二维数组

    int a[2][3]={{1,2,3},{4,5,6}};
    #or int a[2][2]={1,2,3,4};
    

    新的理解:我们可以这样认为,a可以看作是一个一维数组,包含2个元素,每个元素恰好是包含3个整型的元素,a这个名字的值成了指向一个包含3个整型元素的数组的指针(你学过数组指针就该知道,他们是一个道理,后面我会讲解数组指针)

  • 然后开始讨论二维数组和数组名的关系

    a表示的是整个数组的首地址,a[0]表示的是第一行的首地址,这两者在数值上是一样的,但含义不同(或者说类型不同),数组名a是对于整个数组,a[0]是对于第一行。

#打印 a a[0] 的值和 a[0][0] 的地址
cout << a << endl;#0x7ffffffee120
cout << a[0] << endl;#0x7ffffffee120	
cout << &a[0][0] << endl;#0x7ffffffee120

​ 所以a、a[0]的值和 a[0][0]的地址三个表达指向一个地址。

  • 接着看每一行

    cout << a[0] << endl;#0x7ffffffee120
    cout << a[1] << endl;#0x7ffffffee12c
    

    输出的结果是每行的首地址,两个地址之间相差12个字节,也就是三个int的大小。

  • 下面我们通过a[0]&a[0][0]这两个地址推导出其他位置的元素。

    # 由a[0]推出其他,这里以第1行第1列为例
    cout << a[0+1]+1 << endl;			#0x7ffffffee130
    cout << *(a[0+1]+1) << endl;		#5
    cout << a[0]+4 << endl;				#0x7ffffffee130
    cout << *(a[0]+4) << endl;			#5# 由&a[0][0]推出其他, 这里以第1行第1列为例
    cout << &a[0][0]+4<< endl;		#0x7ffffffee130
    cout << *(&a[0][0]+4) << endl;	#5
    

    前两行通过加a[0]的索引得到其他行的首地址,然后再加偏移量得到元素地址,解引用获得该地址的值。

    之后两行是直接计算a[0]的偏移量得到元素地址,解引用获得该元素地址的值。最后两行与直接加偏移量的情况相同。

  • 由数组名得到其他元素

    a
    

    a是数组的名字,它的类型是“指向包含三个整型元素数组的指针”,默认指向第一行。

    a+1
    

    现在它指向了第二行,可以理解为当一个int*的指针指向一个数组的某一个int时,++他便指向了后一个int,同理,这里的数组指针指向了一个数组,所以++他就要指向下一个数组。

    *(a+1

    若是int*解引用后我们拿到了int类型数据,那数组指针呢?实际上我们对一个数组的指针解引用,拿到的是一个数组

    *(a+1== a[1]
    

    *(a+1)就是第二行的数组名,如果你觉得这样表达很奇怪,那么a[1]和他意义相同。

    我们现在拿到这个二维数组的第二行,第二行实际上就是一个一维数组,所以或许我们所有的处理都可以使用一维数组的方式。

    *(a+1+ 1
    

    让他指向了这个数组中的第2个元素。

    **(a+1+ 1

    最后一步就可以拿到想要的值。

    我们来看看一些关于取地址的问题

    printf("%d\n",sizeof(a+1));//8//第二行的地址(指针的大小)
    printf("%d\n",sizeof(&a[0]+1));//8
    printf("%d\n",sizeof(*(&a[0]+1)));//12
    

    1、a是一个数组指针,加一后指向下一行他还是指针,sizeof中就是指针的大小了。

    2、给a[0]取地址?a[0]是一个一维数组的名字,也就是一个指针,再次取地址后的结果就是一个二级指针。而之前我们对数组指针解引用得到数组名,这次刚好相反,所以&arr[0]你可以理解为,我们现在拿到了一个数组指针,对数组指针+1就是让他指向第二行,sizeof中就是指针的大小。(所以数组指针也叫二级指针)

    3、对数组指针解引用拿到了第二行数组的名字,sizeof他就是第二行大小。

  • 最后进行个小测试

    int a[2][3] = {0};
    printf("%d\n",sizeof(a));//24//输出这个二维数组的大小
    printf("%d\n",sizeof(a[0][0]));//4//第一个元素的大小(int)
    printf("%d\n",sizeof(a[0]));//12//第一行的数组的大小
    printf("%d\n",sizeof(a[0]+1));//8//第一行第二个元素的地址(指针的大小)
    printf("%d\n",sizeof(*(a[0]+1)));//4//第一行第二个元素的大小
    printf("%d\n",sizeof(a+1));//8//第二行的地址(指针的大小)
    printf("%d\n",sizeof(*(a+1)));//12//第二行的大小
    printf("%d\n",sizeof(&a[0]+1));//8//第二行的地址(指针的大小)
    printf("%d\n",sizeof(*(&a[0]+1)));//12//第二行的大小
    printf("%d\n",sizeof(*a));//12//第一行的大小
    printf("%d\n",sizeof(a[2]));//12//虽然越界了但是sizeof只是一个关键字他不关心这块空间是否真的存在
    

    数组指针

为了更好的理解指针和二维数组的关系,我们先来定义一个指向 a 的指针变量 p:int (*p)[3] = a;

括号中的*表明 p 是一个指针,它指向一个数组,数组的类型为int [3],这正是 a 所包含的每个一维数组的类型。[ ]的优先级高于*,( )是必须要加的,如果赤裸裸地写作int *p[4],那么应该理解为int *(p[4]),p 就成了一个指针数组,而不是二维数组指针。

对指针进行加法(减法)运算时,它前进(后退)的步长与它指向的数据类型有关,p 指向的数据类型是int [3],那么p+1就前进 3×4 = 12 个字节,p-1就后退 12 个字节,这正好是数组 a 所包含的每个一维数组的长度。也就是说,p+1会使得指针指向二维数组的下一行,p-1会使得指针指向数组的上一行。

指针数组和二维数组指针有着本质上的区别:指针数组是一个数组,只是每个元素保存的都是指针。二维数组指针是一个指针,它指向一个二维数组,以上面的 a为例,它占用 8个字节的内存。

等价关系:

a+i == p+i
a[i] == p[i] == *(a+i) == *(p+i)
a[i][j] == p[i][j] == *(a[i]+j) == *(p[i]+j) == *(*(a+i)+j) == *(*(p+i)+j)

  • 小练习

    int main()
    {int arr[][3] = { 1, 2, 3, 4, 5, 6 };int(*p)[3];p = arr;cout << p[0][0] << " " << *(p[0] + 1) << " " << (*p)[2] << endl;return 0;
    }
    

    1、p[0][0]按照下标访问第一行第一个元素,输出1。
    2、*(p[0] + 1)这个让第一行指针指向第二个元素然后解引用,输出2。
    3、(*p)[2]等同于 *(*p+2),先解引用数组指针拿到第一行数组名,然后加到第3个位置解引用,输出3。

二维数组的传参

  • 使用二维数组的传统定义方法传递参数

    如果把数组名作为函数的参数的话,在编译的时候这个数组参数会自动退化为指针,因此以下两种写法虽然不同,但在编译之后是一样的,数组会退化成数组指针。

#include <iostream>
using namespace std;
/*以下两种写法本质上是一样的*/
int func1(int (*arr)[4]) {arr[0][2] = 20;return 0;
} 
int func2(int arr[][4]) {arr[0][2] = 30;return 0;
}
int main(){int array[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12}; func2(array);cout << array[0][2] << endl;//fun1: 20 or fun2: 30return 0;
}
  • 使用动态分配内存的方式申请空间,可以使用**传递参数

    使用哪种方法定义的就使用哪种方式传参。

#include <iostream>
using namespace std;
int func1(int **arr) {cout << arr[0][1]<< endl;arr[0][2] = 20;    return 0;
}
int main(){int rows=3 ;int cols=4 ;int **arr = new int*[rows];//先使一个二级指针指向数组指针的地址for(int i = 0 ; i < rows ;++i ){arr[i] = new int [cols]();//为一级指针分配地址}arr[0][1]=100;func1(arr);cout << arr[0][2]<< endl;;//释放空间for(int i = 0; i < rows ;++i){delete [] arr[i];//先释放二维数组中每个元素指向的数组arr[i] = NULL;}delete [] arr;//在释放该数组指针;arr = NULL;
}

http://chatgpt.dhexx.cn/article/rqjPvYt1.shtml

相关文章

c语言——二维指针数组

1 一维度数组与指针 1.1一维数组元素在内存分布 #include<stdio.h> #include<stdlib.h> #include<string.h>#define ARRAY_SIZE 8void main() {int data[ARRAY_SIZE]{0,1,2,3,4,5,6,7};int i;printf("data address:0x%-8x\r\n",data);for(i0; i&l…

c++二维数组指针

&#xff11;.定义指针指向二维数组 为了方便根据用户输入动态定义二维数组的行和列&#xff0c;引入变量rowsNum(行)&#xff0c;colsNum(列&#xff09;。 以定义&#xff15;行&#xff14;列的二维数组为例&#xff0c; int rowsNum 4;int colsNum 5;float** a new fl…

二维数组名是指针的指针吗?

我们知道一维数组名是常量指针&#xff0c;我们可以将一维数组名赋给一个指针类型再对一维数组进行相关的操作&#xff0c;那二维数组名又是什么&#xff1f; 我们这样初始化一个二维数组int A[3][3]{1,2,3,4,5,6,7,8}或者为int A[3][3]{ {1,2,3},{4,5,6}&#xff0c;{7,8,9}}…

c++二维数组中指针详解

二维数组 a[2][3]{{1,2,3},{4,5,6}};指针p有如下几种表达形式&#xff1a; 1 方式一&#xff1a;int (*p)[3]a (或&a[0]&#xff09;; 一定要加上括号&#xff0c;因为[]的优先级高于*&#xff1b;意思是定义一个指向3个int类型变量的指针。p代表二维数组中第一个…

C语言 二维数组和指针

二维数组可以看成是元素为一维数组的数组&#xff0c;假设有一个三行四列的二维数组a&#xff0c;它定义为&#xff1a; int a[3][4] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }; a 是二维数组名。a 数组包含 3 行&#xff0c;即 3 个行元素&#xff1a;a[0]&#xff0c;a[1]…

C/C++指向二维数组的指针

1. 二维数组 设有整型二维数组a[3][4]如下&#xff1a;     0 1 2 3     4 5 6 7     8 9 10 11   它的定义为&#xff1a;       int a[3][4]{{0,1,2,3},{4,5,6,7},{8,9,10,11}}  设数组a的首地址为1000&#xff0c;各下标变量的首地址及其值如图所…

二维数组与二级指针

关于二维数组与二级指针那些你必须知道的事 首先,来看一个例子一个error嗯,我是解析指针数组与数组指针 首先,来看一个例子 #include <iostream>using namespace std;int main(void) {int **p;pnew int*[5];for(int i0;i<5;i){p[i]new int[5];}return 0; }不严格地说…

C语言二维数组指针用法

目录 题目 背景概念梳理 一维线性 数组指针 指针步长 数组名与指向其的指针变量名等价 数组的初始化与取元素 数组指针转换关系 解题过程 选项A&#xff1a;* (( * prt1)[2]) 选项B&#xff1a;* ( * (p5)) 选项C&#xff1a;( * prt1)2 选项D&#xff1a; * ( * (…

二维数组指针表示,C语言指针引用二维数组详解

指针变量可以指向一维数组中的元素&#xff0c;当然也就可以指向二维数组中的元素。但是在概念和使用方法上&#xff0c;二维数组的指针比一维数组的指针要复杂一些。要理解指针和二维数组的关系首先要记住一句话&#xff1a;二维数组就是一维数组&#xff0c;这句话该怎么理解…

C语言二维数组指针(指向二维数组的指针)详解

声明&#xff01;本文转载仅为方便学习使用&#xff01; 如有需要&#xff0c;请访问C语言指针数组&#xff08;数组每个元素都是指针&#xff09;详解C语言二维数组指针&#xff08;指向二维数组的指针&#xff09;详解 二维数组在概念上是二维的&#xff0c;有行和列&#x…

c语言 二维数组指针

文章目录 前言一、二维数组指针的定义&#xff1a;二、二维数组指针遍历数组元素&#xff1a;总结 前言 前面我们讲了一维数组指针&#xff0c;今天我们讲一下二维数组指针。 一、二维数组指针的定义&#xff1a; 概述&#xff1a; 二维数组指针的定义就是把一维数组换成二维…

关于二维数组,二维数组指针

最近学习指针&#xff0c;一不小心就掉进了二维数组指针的坑里面&#xff0c;在迷惑了接近一个星期后&#xff0c;我有了以下的总结。&#xff08;希望有大佬看见了能指点指点&#xff0c;我也不知道这么理解到底对不对&#xff0c;虽然我觉得是对的&#xff09; 这是我一开始…

二维数组与指针的关系详解

静态二维数组与指针 我们定义一个二维数组int a[4][3]。 二维数组实际是由多个一维数组组成&#xff0c;在这里&#xff0c;a[3][4]就是由3个长度为4的一维数组组成的二维数组。并且它们在空间上是连续的&#xff0c;相当于一个长为12的一维数组。 这里a&#xff0c;a[i]全部…

二维数组与指针(详解)

如果对字符串和二维数组有基本概念可以直接跳去看他们的关系及使用 于4.3 00:08修改&#xff0c;改正了之前文章中错误的观点&#xff0c;修改了一些低级错误 欢迎大家在文章下留言 于21-05-19 22:37再次更新,前几天有个同学问了我这么个问题&#xff0c;我觉得是一个非常好的…

C/C++二维数组指针(指向二维数组的指针)详解

多维数组与指针 用指针变量可以指向一维数组中的元素&#xff0c;也可以指向多维数组中的元素。1) 多维数组元素的地址 设有一个二维数组 a&#xff0c;它有 3 行 4 列。它的定义为&#xff1a; int a[3][4]{{1,3,5,7},{9,11,13,15},{17,18,21,23}}; a 是一个数组名。a 数…

C语言 指针+二维数组详解 (应付期末、考研的最强笔记,建议收藏)

哈喽&#xff01;这里是一只派大鑫&#xff0c;不是派大星。本着基础不牢&#xff0c;地动山摇的学习态度&#xff0c;从基础的C语言语法讲到算法再到更高级的语法及框架的学习。更好地让同样热爱编程(或是应付期末考试 狗头.jpg)的大家能够在学习阶段找到好的方法、路线&#…

多任务Multitask Learning

一次只学习一个任务&#xff0c;大部分机器学习都属于单任务学习。 多任务学习&#xff1a;把多个相关的任务放在一起学习&#xff0c;同时学习多个任务。 对于复杂的问题&#xff0c;可以分解为简单的相互独立的子问题来解决&#xff0c;然后再合并结果&#xff0c;得到最初复…

Distral: Robust multitask reinforcement learning.

作者&#xff1a;张楚珩 链接&#xff1a;https://zhuanlan.zhihu.com/p/51091244 来源&#xff1a;知乎 著作权归作者所有。商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处。 中Distral是Distill & transfer learning的缩写。 原文传送门 Teh, Yee, et…

论文阅读笔记--Clustered Federated Learning:Model-Agnostic Distributed Multitask Optimization Under Privacy

Introduction 传统的Parameter Server&#xff08;P-S&#xff09;架构的联邦学习系统尝试训练出一个模型&#xff0c;让它能适用于每一个client的数据分布&#xff0c;这暗含了一个假设&#xff0c;模型的最优解 θ ∗ \theta^* θ∗同时是所有client的最优解&#xff0c;各个…

CVPR 2021 UniT: Multimodal Multitask Learning with a Unifified Transformer

动机 transformer在包括但不限于自然语言、图像、视频和音频在内的广泛领域都显示出巨大的成功。 前人的研究表明,在大型语料库中训练的transformer在一系列的下游语言任务中学习了强大的表征。在视觉领域中,基于transformer的模型在图像分类、目标检测和全景分割方面取得了非…