二维数组

在说二维数组前先来说下一维数组中的指针数组和和数组的指针

一、一维数组中指针数组和数组指针的区别

指针数组:

 int *p[];

[]的优先级比*高,首先它是一个数组,它的大小是5,它里面存放的数据类型是int *,也就是整型指针。 所以它叫指针数组,讲到底这个p是一个数组,数组内的元素是5个指针,而数组内的每一个指针指向一个int型的变量

数组的指针:

int (*p)[];

首先p是一个指针,指向大小为5的数组,因此这叫数组的指针,定义了一个指向5个元素的一维数组的指针。(括号优先)

二、两者在赋值时的区别

指针数组的赋值

 #include <stdio.h>

 main()
{
int *p[];
int a = ; p[] = &a;
printf("%d", *p[]);
}

数组的指针的赋值

 main()
{
int (*p)[];
int a[] = {, , , , }; p = &a;
printf("%d", *p[]);
}

三、关于数组的地址(这里只讨论一维\二维数组)

一维数组

 int a[];

a表示的是数组的首地址,a等价于&a[0]

二维数组

 int a[][] = {, , , };

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

对二者(a、a[0])的地址是否相同进行验证

 #include <stdio.h>

 int main()
{
int a[][] = {, , , }; printf("%p\n%p\n", a, a[]); return ;
}

运行结果

在用数组的地址进行赋值的时候,虽然三者值相同,但是三者不可随意混用(以int a[2][2]为例)

a--------是int (*)[2]型

a[0]-----是int *型

对于a[0]和&a[0][0],两个类型都是int *型的,所以下述两种赋值方法等价

第一种:

 int a[][] = {, , , };
int *p;
p = a[];

第二种:

 int a[][] = {, , , };
int *p;
p = &a[][];

对于int a[2][2]来说,如果将a[0]改为&a[0],那么&a[0]和a的类型相同,都为int (*)[2]类型,下面以int a[5][5]为例,列出了二维数组的元素在不同方式表达下的不同类型

也可以用一维指针数组来保存二维数组中某个元素的地址

 int a[][] = {, , , };
int *p[];
p[] = &a[][];
printf("%d", *p[]);

四、二维数组的解引用

以二维数组a[2][3]={1, 2, 3, 4 ,5, 6};为例(第一维是行,第二维是列)

第一种:*(*a+1)--------等价于a[0][1],因为*的优先级比+高,所以先解引用,进入第二维在第二维里面地址+1,再次解引用得到元素值

第二种:*(*(a+1))------等价于a[1][0],比上面第一种多加了一个括号,括号优先级最高,先+1移动地址(注意是在第一维里面移动),然后解引用进入第二维,再解引用得到元素的值

第三种:*(&a[0][0]+1)--等价于a[0][1],这里使用了&取地址符,将原本表示第一个元素的a[0][0]返回到第二个维度,然后第二维地址+1,再解引用得到元素的值

为方便读者理解下面上图

补充:

请读者先看下面的代码

 #include <stdio.h>

 main()
{
int a[][] = {, , , , , }; printf("%d***%d", *(a[]+), (*a+)[]);
}

*(a[1]+1)--------表示的是a[1][1]的值

(*a+1)[1]--------表示的是a[0][2]的值

为了方便描述先退回一维数组,以int a[5]来说,a表示的数组a的首地址,a[2]表示在a的基础上移动2个地址(注意a的类型是int *型的),再解引用得到元素的值,意思是a[2]

实际上包含了两步,第一步地址移动,第二步解引用得到元素的值(注意第二步,有点隐式转换的意思,经常被人忽略)

现在来解释上面的二维数组就容易多了

先来看第一个*(a[1]+1),a[1]代表第二行的首地址,注意这里的维度已经是第二维度了,然后括号优先第二维地址+1,最后解引用得到元素的值

来看第二个(*a+1)[1],这里提一句,因为[]的优先级是比*高的所以这里的括号不能去掉,第一步先解引用进入第二维度(*优先级高于+),然后第二维地址+1,然后再在当前基础上再移动一次地址,最后解引用

得到元素的值,这里可能有点绕,换个说法就是[1]是在当前维度进行移动,然后解引用(“当前维度”有点不太严谨,为了方便理解先将就这么用了)

拿a[2][1]来说,一共有四步,其中包含了两次地址移动,两次解引用,执行顺序是:地址移动->解引用->地址移动->解引用(这里提一句,[]的结合性是左结合的,所以在移动的时候先移动行(第一维)再移动列(第二维),小声BB)

详细步骤:第一步:在当前维度地址+2,因为a的维度是第一维,所以是第一维地址+2,即行+2

     第二步:解引用进入第二维度

     第三步:在当前维度地址+1,因为这时已经进入第二维,所以第二维地址+1,即列+1

     第四步:解引用得到元素的值  

二维数组(解引用、指针数组、数组的指针)——C语言的更多相关文章

  1. Gym 102028J 扫描线/二维差分 + 解方程

    题意:有一个二维平面,以及n个操作,每个操作会选择一个矩形,使得这个二维平面的一部分被覆盖.现在你可以取消其中的2个操作,问最少有多少块地方会被覆盖? 思路:官方题解简洁明了,就不细说了:https: ...

  2. [luogu4479][BJWC2018]第k大斜率【二维偏序+二分+离散化+树状数组】

    传送门 https://www.luogu.org/problemnew/show/P4479 题目描述 在平面直角坐标系上,有 n 个不同的点.任意两个不同的点确定了一条直线.请求出所有斜率存在的直 ...

  3. 【二维偏序】【树状数组】【权值分块】【分块】poj2352 Stars

    经典问题:二维偏序.给定平面中的n个点,求每个点左下方的点的个数. 因为 所有点已经以y为第一关键字,x为第二关键字排好序,所以我们按读入顺序处理,仅仅需要计算x坐标小于<=某个点的点有多少个就 ...

  4. 摩托罗拉SE4500 德州仪器TI Omap37xx/AM3715/DM3730/AM3530 wince6.0/Windows Mobile 6.5平台 二维软解调试记录及相关解释

    现在安卓大行其道,不是高通,就是MTK,甚至于很多人不知道还有德州仪器这个平台了,关于如何在德州仪器Omap37xx平台上调试SE4500,网络上除了针对SE4500的几个pdf文档介绍之外,没有任何 ...

  5. java基础5 (一维)数组和二维数组

    本文知识点(目录): 一维数组(一维数组的概念.优点.格式.定义.初始化.遍历.常见异常.内存分析以及常见操作(找最大值.选择排序.冒泡排序等等))    二维数组(二维数组的遍历.排序.查找.定义. ...

  6. 数组(Array),二维数组,三维数组

    数组(Array):相同类型数据的集合就叫做数组. (一)定义数组的方法: A) type[] 变量名 = new type[数组中元素的个数] 例如: int[] a = new int[10] ; ...

  7. java se系列(四) 函数、数组、排序算法、二分法、二维数组

    1 函数 1.1  数的概述 发现不断进行加法运算,为了提高代码的复用性,就把该功能独立封装成一段独立的小程序,当下次需要执行加法运算的时候,就可以直接调用这个段小程序即可,那么这种封装形形式的具体表 ...

  8. 《Java大学教程》—第16章 二维数组

    多维(Multi-dimensional)数组维数由索引个数决定.常用的数组:一维(one-dimensional)数组.二维(two-dimensional)数组 16.2    创建二维数组索引从 ...

  9. 树状数组+二维前缀和(A.The beautiful values of the palace)--The Preliminary Contest for ICPC Asia Nanjing 2019

    题意: 给你螺旋型的矩阵,告诉你那几个点有值,问你某一个矩阵区间的和是多少. 思路: 以后记住:二维前缀和sort+树状数组就行了!!!. #define IOS ios_base::sync_wit ...

  10. C语言中指针和数组

    C语言数组与指针的那些事儿 在C语言中,要说到哪一部分最难搞,首当其冲就是指针,指针永远是个让人又爱又恨的东西,用好了可以事半功倍,用不好,就会有改不完的bug和通不完的宵.但是程序员一般都有一种迷之 ...

随机推荐

  1. Codeforces 1238E. Keyboard Purchase

    传送门 注意到 $m$ 只有 $20$ ,考虑一下状压 $dp$ 设 $f[S]$ 表示当前确定的字符集合为 $S$ ,那么转移就考虑从最右边加入的下一个字符 $c$ 那么问题来了,代价如何计算 考虑 ...

  2. Codeforces 869E. The Untended Antiquity (二维Fenwick,Hash)

    Codeforces 869E. The Untended Antiquity 题意: 在一张mxn的格子纸上,进行q次操作: 1,指定一个矩形将它用栅栏围起来. 2,撤掉一个已有的栅栏. 3,询问指 ...

  3. P2341 [HAOI2006]受欢迎的牛(更完)

    P2341 [HAOI2006]受欢迎的牛 题解 tarjan 缩点板子题 如果 A 稀饭 B,那就 A 向 B 连边,构造出一个有向图 如果这个有向图里有强连通分量,也就说明这个强连通分量里的所有奶 ...

  4. 摘抄java基础

    1.Java中Static的相关用法总结?(静态方法:静态变量:静态代码块) public static void main(String args[])执行的关键,在于有static.有了stati ...

  5. [Java读书笔记] Effective Java(Third Edition) 第2章 创建和销毁对象

      第 1 条:用静态工厂方法代替构造器 对于类而言,获取一个实例的方法,传统是提供一个共有的构造器. 类可以提供一个公有静态工厂方法(static factory method), 它只是一个返回类 ...

  6. [Java复习] 多线程 Multithreading

    Q1多线程基础 进程和线程? 进程: 1. 一段程序执行过程,动态的,相对而言程序是静态的.(与类和对象的关系类似) 2. CPU资源分配最小单元,包括CPU调度和资源管理. 3. 一个进程可以有多个 ...

  7. WEditor使用方法

    APP的定位方式有: 1. Appium Desktop工具里的Inspector 2. /tools/bin/uiautomatorviewer.bat 最近发现在一个更好用的定位工具: Wedit ...

  8. 自定义nagios监控脚本---磁盘检测

    自定义nagios监控脚本---磁盘检测 1. 在客户端上创建脚本/usr/local/nagios/libexec/check_disk.shvim /usr/local/nagios/libexe ...

  9. React Native创建项目等待时间长解决

    1. 初始化工程 在终端输入命令 :react-native init AwesomeProject 从命令上看,看起来是初始化一个工程,于是, 1分钟...... 10分钟...... 1小时... ...

  10. java数据机构之自定义栈

    一.栈的特点 1.线性数据结构 2.后进先出 二.使用数组来实现栈 //使用数组来实现栈 public class MyArrayStack<E> { //保存数据 private Obj ...