目录

题目

背景概念梳理

一维线性

数组指针

指针步长

数组名与指向其的指针变量名等价

数组的初始化与取元素

数组指针转换关系

解题过程

选项A:* (( * prt+1)[2])

选项B:* ( * (p+5))

选项C:( * prt+1)+2

选项D: * ( * (a+1)+2)

正确答案

整体代码

参考链接


题目

设有以下定义:

int a[4][3] = {1,2,3,4,5,6,7,8,9,10,11,12};
int (*prt)[3] = a, *p = a[0];

则以下能够正确表示数组元素a[1][2]的表达式是()

A. * (( * prt+1)[2])
B. * ( * (p+5))
C. ( * prt+1)+2
D. * ( * (a+1)+2)

链接:设有以下定义: a[4][3]={1,2,3,4,5,6__牛客网,来源:牛客网

背景概念梳理

以本题为例,二维数组a[4][3],所表示的元素排列如下:

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

a[4][3]可理解为“一个四行三列的数组”,亦可理解为“数组a包含4个数组元素,每个数组元素包含三个整形元素”

一维线性

内存中,a 的分布是一维线性的,整个数组占用一块连续的内存,C语言中的二维数组是按行排列的,也就是先存放 a[0] 行,再存放 a[1] 行,最后存放 a[2] 行;每行中的 3 个元素也是依次存放。数组 a 为 int 类型,每个元素占用 4 个字节,整个数组共占用 4×(3×4) = 48 个字节。

C语言允许把一个二维数组分解成多个一维数组来处理。对于数组 a,它可以分解成三个一维数组,即 a[0]、a[1]、a[2]、a[3]。每一个一维数组又包含了 43个元素,例如 a[0] 包含 a[0][0]、a[0][1]、a[0][2]。

数组指针

int (*prt)[3] = a;

括号中的*表明 prt 是一个指针变量,它指向某数组,这个数组的类型为int [3](即这个数组是一个包含三个元素的数组),这正是 a 所包含的每个一维数组的类型。指针prt指向a的首个一维数组。

指针步长

prt是一个指向数组的指针,指针的步长取决于其指向的数据变量的大小,prt指向的是一个数组类型为int[3]的数组,那么其数据结构大小为(3*4)=12字节,即prt在当前情况下,步长为12,(prt+1),(prt-1),所指向的数据内存地址,各差12。

数组名与指向其的指针变量名等价

数组名表示数组的第一个元素的地址,可将其看作是一个指针常量。而这个指针常量所指向的类型与数组元素的类型一致。在本题中,prt作为指向数组a的第一个元素的地址的指针变量名,数组a的数组名"a"亦表示其数组的第一个元素的地址,两个都是指向数组a的第一个元素的地址,故数组名 a 在表达式中也会被转换为和 prt 等价的指针。

数组的初始化与取元素

以一维数组为例,初始化的时候"[]"中,所填的数值是要给数组分配几个元素的位置;取元素时,“[]”中,所填的数值是要获取那个索引值的元素,数组的索引值都是从零开始的。“[]”中所填的数值,在数组初始化和取元素时所表达的含义完全不一样。

//初始化
int num[5]; //数组 num 中有 5 个元素,每个元素都是 int 型变量,而且它们在内存中的地址是连续分配的 //取元素
int n1 = num[0];//获取num数组的第零个元素
int n2 = num[1];//获取num数组的第一个元素
int n3 = num[2];//获取num数组的第二个元素
int n4 = num[3];//获取num数组的第三个元素
int n5 = num[4];//获取num数组的第四个元素

数组指针转换关系

int a[4][3];
int (*p)[3] = a;//0<=i<=3, 0<=j<=2
a+i == p+i
a[i] == *(a+i) //a[i]等价于从数组a的首地址向后数第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)

解题过程

依题,a[1][2]所对应的值是6,按选项逐个分析:

选项A:* (( * prt+1)[2])

*prt表示的是数组a第一个数组元素的地址=数组a的首地址,

(*prt+1)表示数组a中第二个整形元素的地址(在这里prt发生了退化,指向的是数组a中的首个数组元素的首个整形元素,实际运行结果,*prt与(*prt+1)差4字节,可佐证),

(*prt+1)[2]表示数组a第二个整形元素向后跨两个索引的值,

* (( * prt+1)[2])表示数组a第二个整形元素向后跨两个索引的值作为指针变量所指向的变量,

int main()
{int a[4][3] = {1,2,3,4,5,6,7,8,9,10,11,12};int (*prt)[3] = a, *p = a[0];printf("a[1][2]: %d\n",a[1][2]); //[]的作用 printf("\nA: *prt: %d\n",*prt);printf("A:(*prt+1): %d\n",(*prt+1));printf("A:(*prt+1)[2]: %d\n",(*prt+1)[2]);//printf("*((*prt+1)[2]): %d\n",*((*prt+1)[2])); //直接报错
} 

另外,做了一个关于指针退化的实验,*(prt+1)指向的是数组a的第二个数组元素(实验佐证,sizeof指针长度为12),但当再其基础上做加1处理后,其就退化成了指向第二行的首个数据的指针。

     printf("\nAtry: *(prt+1): %d\n",*(prt+1));printf("Atry: sizeof(*(prt+1)): %d\n",sizeof(*(prt+1))); //说明*(prt+1)获取的是第二行的数据printf("Atry: *(prt+1)+1: %d\n",*(prt+1)+1);//*(prt+1)退化成了第二行的第一个数据的地址, printf("Atry: ((*(*(prt+1)+1)): %d\n",(*(*(prt+1)+1)));

关于数组指针退化的问题,当直接对数组指针变量进行操作(eg. *(prt+1))后再解引用,都不会导致指针退化。除此之外,都会退化到指向某个整形元素。具体原因,*(prt+1)单独使用时表示的是第 1 行数据,放在表达式中会被转换为第 1 行数据的首地址,也就是第 1 行第 0 个元素的地址,因为使用整行数据没有实际的含义,编译器遇到这种情况都会转换为指向该行第 0 个元素的指针;就像一维数组的名字,在定义时或者和 sizeof、& 一起使用时才表示整个数组,出现在表达式中就会被转换为指向数组第 0 个元素的指针。

选项B:* ( * (p+5))

指针p直接指向的数组a的首个数组元素的首个整形元素,因为指针p的数据类型是int,

*(p+5)表示从数组a的首个数组元素的首个整形元素向后数的第5个整形元素的指针所指向的值,

*(*(p+5))表示从数组a的首个数组元素的首个整形元素向后数的第5个整形元素的指针所指向的值作为指针变量所指向的值(不存在嘛!直接报错)。

 //printf("*(*(p+5)): %d\n",*(*(p+5))); //直接报错 printf("\nB: (*(p+5)): %d\n",(*(p+5)));  printf("B: (p+5): %d\n",(p+5));

选项C:( * prt+1)+2

*prt表示数组a的首个元素对应的地址

(*prt+1)表示数组a的第二个元素对应的地址

( * prt+1)+2表示数组a的第4个元素对应的地址

只有再在其基础上,再加一层解引用,才可以表示数组a的第4个元素对应的值

 printf("\nC: *prt: %d\n",*prt);printf("C: (*prt+1): %d\n",(*prt+1));printf("C: (*prt+1)+2: %d\n",(*prt+1)+2);printf("C: *((*prt+1)+2): %d\n",*((*prt+1)+2)); //只有再在其基础上,再加一层解引用,才可以表示数组a的第4个元素对应的值

选项D: * ( * (a+1)+2)

a等同于prt,

*(a+1)表示数组a的第二个数组元素的地址,

*(a+1)+2,发生指针退化,*(a+1)此时表示数组a的第二个数组元素中的首个整形元素的地址,整个表示数组a第二行的第二个元素的地址

* ( * (a+1)+2)表示数组a第二行的第二个元素的值

     printf("\nD: *(a+1): %d\n",*(a+1));printf("D: (*(a+1)+2): %d\n",(*(a+1)+2));printf("D: *(*(a+1)+2): %d\n",*(*(a+1)+2));printf("\nD: *(a): %d\n",*(a));printf("D: *(a+1): %d\n",*(a+1));printf("D: *(*a+1): %d\n",*(*a+1));

正确答案

选D,* ( * (a+1)+2)

整体代码

int main()
{int a[4][3] = {1,2,3,4,5,6,7,8,9,10,11,12};int (*prt)[3] = a, *p = a[0];printf("a[1][2]: %d\n",a[1][2]); //[]的作用 //printf("*((*prt+1)[2]): %d\n",*((*prt+1)[2]));printf("\nAtry: *(prt+1): %d\n",*(prt+1));printf("Atry: sizeof(*(prt+1)): %d\n",sizeof(*(prt+1))); //说明*(prt+1)获取的是第二行的数据printf("Atry: *(prt+1)+1: %d\n",*(prt+1)+1);//*(prt+1)退化成了第二行的第一个数据的地址, printf("Atry: ((*(*(prt+1)+1)): %d\n",(*(*(prt+1)+1)));printf("\nA: *prt: %d\n",*prt);printf("A:(*prt+1): %d\n",(*prt+1));printf("A:(*prt+1)[2]: %d\n",(*prt+1)[2]);//printf("*((*prt+1)[2]): %d\n",*((*prt+1)[2])); //直接报错 //printf("*(*(p+5)): %d\n",*(*(p+5))); //直接报错 printf("\nB: (*(p+5)): %d\n",(*(p+5)));  printf("B: (p+5): %d\n",(p+5));printf("\nC: *prt: %d\n",*prt);printf("C: (*prt+1): %d\n",(*prt+1));printf("C: (*prt+1)+2: %d\n",(*prt+1)+2);printf("C: *((*prt+1)+2): %d\n",*((*prt+1)+2)); //只有再在其基础上,再加一层解引用,才可以表示数组a的第4个元素对应的值printf("\nD: *(a+1): %d\n",*(a+1));printf("D: (*(a+1)+2): %d\n",(*(a+1)+2));printf("D: *(*(a+1)+2): %d\n",*(*(a+1)+2));printf("\nD: *(a): %d\n",*(a));printf("D: *(a+1): %d\n",*(a+1));printf("D: *(*a+1): %d\n",*(*a+1));
} 

参考链接

数组的定义,初始化和使用,C语言数组详解数组可以说是目前为止讲到的第一个真正意义上存储数据的结构。虽然前面学习的变量也能存储数据,但变量所能存储的数据很有限。不仅如此,数组和指针(后续会讲)是相辅相成的http://c.biancheng.net/view/184.html

C语言二维数组指针(指向二维数组的指针)详解二维数组在概念上是二维的,有行和列,但在内存中所有的数组元素都是连续排列的,它们之间没有缝隙。以下面的二维数组 a 为例: int a[3][4] = { {0, 1, 2, 3}, {4, 5, 6, 7}, {8, 9, 10, 11} }; 从http://c.biancheng.net/view/2022.html

C语言二维数组指针用法相关推荐

  1. C语言 二维数组的用法,二维数组方法用法 _C语言-w3school教程

    C语言 的 二维数组 C语言中的二维数组以行和列的形式表示,也称为矩阵. 它也被称为阵列数组或数组列表. 二维,三维或其他维度数组也称为多维数组. 二维数组声明 我们可以用以下方式在C语言中声明一个数 ...

  2. java二维数组扫雷,C语言二维数组实现扫雷游戏

    #include //使用二维数组实现 扫雷 int main() { char ui[8][8]={ '+','+','+','+','+','+','+','+', '+','+','+','+' ...

  3. c语言二维数组 ppt,C语言二维数组与指针.ppt

    C语言二维数组与指针.ppt 好好考,全国计算机等级考试 二级C语言,第12讲 二维数组与指针,二维数组的定义 数组元素的引用及初始化 二维数组和指针 二维数组名和指针数组作为实参 二维数组程序举例 ...

  4. c语言多维数组指针地址讲解,C语言入门之多维数组的指针变量

    一.多维数组地址的表示方法 设有整型二维数组a[3][4]如下: 0 1 2 3 4 5 6 7 8 9 10 11 设数组a的首地址为1000,各下标变量的首地址及其值如图所示. 在前面曾经介绍过, ...

  5. C语言 二维数组遍历 - C语言零基础入门教程

    目录 一.计算一维数组长度 二.计算二维数组长度 1.二维数组行数 2.二维数组列数 3.二维数组的元素个数 = 二维数组行数 * 二维数组列数 三.猜你喜欢 零基础 C/C++ 学习路线推荐 : C ...

  6. c语言二维数组a中,a,a[0],a[0][0]的值与值的类型

    c语言二维数组中的一些表达式的值与意义的问题 前两天写代码的时候遇到一些关于数组的问题,进而对二维数组进行了一些深入的思考.想到了一个有意思的问题. 在二维数组a中,&a,&a[0], ...

  7. C语言二维数组的四种遍历方式

    二维数组的四种遍历方式: a[i][j]   *(a[i]+j)   *(*(a+i)+j)    *(&a[0][0]+i*n+j)  1.a[i][j] :  这种方法是最基本的方式. 2 ...

  8. c语言如何初始化程序,c语言二维数组如何初始化为0 - 全文

    c语言二维数组如何初始化 1 有两种方法 (1)在定义时可以直接赋值来初始化 (2)在定义后可以为其元素一个个来赋值 2 示例 123456789101112131415161718192021222 ...

  9. C语言 | 二维数组作为函数参数

    1024G 嵌入式资源大放送!包括但不限于C/C++.单片机.Linux等.关注微信公众号[嵌入式大杂烩],回复1024,即可免费获取! 偶然间发现C语言二维数组作为函数的参数是个比较容易出错的问题. ...

  10. c语言定二维义数组,C语言二维数组超细讲解

    用一维数组处理二维表格,实际是可行的,但是会很复杂,特别是遇到二维表格的输入.处理和输出. 在你绞尽脑汁的时候,二维数组(一维数组的大哥)像电视剧里救美的英雄一样显现在你的面前,初识数组的朋友们还等什 ...

最新文章

  1. 基于模型(Model-based)进行特征选择(feature selection)并可视化特征重要性(feature importance)
  2. PostgreSQL — 数据库实例只读锁定
  3. linux用户、组、权限问题
  4. iou画 yolov3_专栏 | 【从零开始学习YOLOv3】4. YOLOv3中的参数进化
  5. ▲数据结构 笛卡尔树【2011】五2 C++版
  6. Win11如何将游戏隐藏 Win11游戏隐藏的方法
  7. MySQL 添加、查看字段注释
  8. TikTok全球月活突破10亿
  9. python 安装 setuptools Compression requires the (missing) zlib module 的解决方案
  10. 【java】随机数的阶乘
  11. 关于mysql查询_关于mysql的查询
  12. oracle中常用的方法,oracle常用方法
  13. html画圆圈加感叹号,感叹号怎么打 拜托了是两个并在一起的叹号,
  14. Excel催化剂100+大主题功能梳理导读
  15. 电脑做照片视频的软件用哪个?3步制作高清照片视频,超多酷炫转场效果
  16. 大牛教学 | 在51单片机上用C语言实现循环点亮8盏LED灯
  17. 虚拟服务器 vmotion,不使用 vMotion 将 VMware 虚拟机从一台主机迁移至另一台主机...
  18. 折纸 瓦力机器人_一张纸成千种形态机器人:折纸机器人,神奇的创造
  19. 如何加入Apache开源社区:Apache ServiceComb (incubating) 微服务开源项目实例讲解
  20. malock 一个面向局域网的 “分布式 CA* 系统”

热门文章

  1. php连接mysql超时问题
  2. Windows设置自己的程序开机自动启动
  3. 定点运算之补码一位乘法(Booth算法)
  4. 免费批量化音频切割软件 AutoVoiceCut
  5. w7计算机 里工具栏没有了,win7电脑任务栏不见了怎么办
  6. 【从Northwind学习数据库】数据更新
  7. intel hd3000 本 在 64位 ubuntu10.04 下 液晶亮度无法调节 的解决之道(亲测)
  8. 3d显卡2003测试软件,3DMark 2003
  9. android 让程序在后台运行,android – 如何让我的应用程序在后台运行?
  10. linux查看录音驱动程序,Linux 下查看麦克风或音频采集设备