当前位置: 首页 > news >正文

C/C++——二维数组与指针、指针数组、数组指针(行指针)、二级指针的用法...

本文转载自:https://blog.csdn.net/qq_33573235/article/details/79530792

 

 


1. 二维数组和指针

 

要用指针处理二维数组,首先要解决从存储的角度对二维数组的认识问题。我们知道,一个二维数组在计算机中存储时,是按照先行后列的顺序依次存储的,当把每一行看作一个整体,即视为一个大的数组元素时,这个存储的二维数组也就变成了一个一维数组了。而每个大数组元素对应二维数组的一行,我们就称之为行数组元素,显然每个行数组元素都是一个一维数组

下面我们讨论指针和二维数组元素的对应关系,清楚了二者之间的关系,就能用指针处理二维数组了。
设p是指向二维数组a[m][n]的指针变量,则有:

int* p=a[0];//此时P是指向一维数组的指针。P++后,p指向 a[0][1]。

如果定义int (*p1)[n];p1=a;p1++后,p1指向a[1][0];  

则p+j将指向a[0]数组中的元素a[0][j]。
由于a[0]、a[1]┅a[M-1]等各个行数组依次连续存储,则对于a数组中的任一元素a[i][j],指针的一般形式如下:
p+i*N+j             相应的如果用p1来表示,则为*(p1+i)+j
元素a[i][j]相应的指针表示为:
*( p+i*N+j)        相应的如果用p1来表示,则为*(*(p1+i)+j)
同样,a[i][j]也可使用指针下标法表示,如下:
p[i*N+j]
例如,有如下定义:
int a[3][4]={{10,20,30,40,},{50,60,70,80},{90,91,92,93}};
则数组a有3个元素,分别为a[0]、a[1]、a[2]。而每个元素都是一个一维数组,各包含4个元素,如a[1]的4个元素是a[1][0]、a[1][1]、a[1]2]、a[1][3]。
若有:
int *p=a[0];
则数组a的元素a[1][2]对应的指针为:p+1*4+2
元素a[1][2]也就可以表示为:*( p+1*4+2)
用下标表示法,a[1][2]表示为:p[1*4+2]
特别说明:
对上述二维数组a,虽然a[0]、a都是数组首地址,但二者指向的对象不同,a[0]是一维数组的名字,它指向的是a[0]数组的首元素,对其进行“*”运算,得到的是一个数组元素值,即a[0]数组首元素值,因此,*a[0]与a[0][0]是同一个值;而a是一个二维数组的名字,它指向的是它所属元素的首元素,它的每一个元素都是一个行数组,因此,它的指针移动单位是“行”,所以a+i指向的是第i个行数组,即指向a[i]。对a进行“*”运算,得到的是一维数组a[0]的首地址,即*a与a[0]是同一个值。当用int *p;定义指针p时,p的指向是一个int型数据,而不是一个地址,因此,用a[0]对p赋值是正确的,而用a对p赋值是错误的。这一点请读者务必注意。
 
 

2. 用二维数组名作地址表示数组元素。

 
另外,由上述说明,我们还可以得到二维数组元素的一种表示方法:
对于二维数组a,其a[0]数组由a指向,a[1]数组则由a+1指向,a[2]数组由a+2指向,以此类推。因此,*a与a[0]等价、*(a+1)与a[1]等价、*(a+2)与a[2]等价,┅,即对于a[i]数组,由*(a+i)指向。由此,对于数组元素a[i][j],用数组名a的表示形式为:
*(*(a+i)+j)
指向该元素的指针为:
*(a+i)+j

数组名虽然是数组的地址,但它和指向数组的指针变量不完全相同。

第一,指针变量的值可以改变,即它可以随时指向不同的数组或同类型变量,而数组名自它定义时起就确定下来,不能通过赋值的方式使该数组名指向另外一个数组。

第二,数组名是指针,类型是指向元素类型的指针,但值是指针常量,声明数组时编译器会为声明所指定的元素数量保留内存空间。数组指针是指向数组的指针,声明指针变量时编译器只为指针本身保留内存空间。

例4 求二维数组元素的最大值。


该问题只需对数组元素遍历,即可求解。因此,可以通过顺序移动数组指针的方法实现。
main()
{
int a[3][4]={{3,17,8,11},{66,7,8,19},{12,88,7,16}};
int *p,max;
for(p=a[0],max=*p;p<a[0]+12;p++)
   if(*p>max)
      max=*p;
printf("MAX=%d/n",max);
}
执行结果:
MAX=88
这个程序的主要算法都是在for语句中实现的:p是一个int型指针变量;p=a[0]是置数组的首元素地址为指针初值;max=*p将数组的首元素值a[0][0]作为最大值初值;p<a[0]+12是将指针的变化范围限制在12个元素的位置内;p++使得每比较一个元素后,指针后移一个元素位置。
例5 求二维数组元素的最大值,并确定最大值元素所在的行和列。
本例较之上例有更进一步的要求,需要在比较的过程中,把较大值元素的位置记录下来,显然仅用上述指针移动方法是不行的,需要使用能提供行列数据的指针表示方法。
main()
{
int a[3][4]={{3,17,8,11},{66,7,8,19},{12,88,7,16}};
int *p=a[0],max,i,j,row,col;
max=a[0][0];
row=col=0;
for(i=0;i<3;i++)
   for(j=0;j<4;j++)
     if(*(p+i*4+j)>max)
      {
        max=*(p+i*4+j);
        row=i;
        col=j;
      }
printf("a[%d][%d]=%d/n",row,col,max);
}
程序运行结果:
a[2][1]=88

 


3. 行数组指针

 

在上面的说明中我们已经知道,二维数组名是指向行的,它不能对如下说明的指针变量p直接赋值:

int a[3][4]={{10,11,12,13},{20,21,22,23},{30,31,32,33}},*p;
其原因就是p与a的对象性质不同,或者说二者不是同一级指针。C语言可以通过定义行数组指针的方法,使得一个指针变量与二维数组名具有相同的性质。行数组指针的定义方法如下:
数据类型 (*指针变量名)[二维数组列数];
例如,对上述a数组,行数组指针定义如下:
int (*p)[4];
它表示,数组*p有4个int型元素,分别为(*p)[0]、(*p)[1]、(*p)[2]、(*p)[3] ,亦即p指向的是有4个int型元素的一维数组,即p为行指针

此时,可用如下方式对指针p赋值:

p=a;

 

 


4. 指针数组的定义

 

指针数组是指每个元素中存放的是指针。定义为 int *p[4];sizeof(p)=16,返回的是数组的总空间

 


5. 二级指针

 

二级指针 :int**ptr:数据类型是int**,即指向指针的指针。

 

转载于:https://www.cnblogs.com/oddcat/p/9701518.html

相关文章:

  • 程序员的迷茫期
  • Java集合源码学习(1)接口
  • 微信小程序【树形视图】demo
  • 使用JTAG调试器和Freemaster 2.0 进行powerpc架构的mpc5XXX系列的调试
  • EM算法随记
  • Vue 字段验证 八
  • 批量ping 检测linux主机是否可以通
  • find详细参数
  • PostgreSQL 10.1 手册_部分 III. 服务器管理_第 18 章 服务器设置和操作_18.9. 用 SSL 进行安全的 TCP/IP 连接...
  • PostgreSQL 10.1 手册_部分 III. 服务器管理_第 23 章 本地化_23.2. 排序规则支持
  • 最近关于虚拟机的学习
  • Linux的systemd特性及gawk使用
  • 新东方雅思词汇---7.3、dioxide
  • 阿里云最新一代GPU云主机GN6(V100机型)正式售卖
  • 还原一个 Windows 10 Metro 布局
  • [rust! #004] [译] Rust 的内置 Traits, 使用场景, 方式, 和原因
  • 《微软的软件测试之道》成书始末、出版宣告、补充致谢名单及相关信息
  • 2017年终总结、随想
  • CoolViewPager:即刻刷新,自定义边缘效果颜色,双向自动循环,内置垂直切换效果,想要的都在这里...
  • emacs初体验
  • JavaScript的使用你知道几种?(上)
  • JavaScript类型识别
  • js正则,这点儿就够用了
  • leetcode98. Validate Binary Search Tree
  • Next.js之基础概念(二)
  • PAT A1120
  • Rancher如何对接Ceph-RBD块存储
  • React-redux的原理以及使用
  • vue从创建到完整的饿了么(18)购物车详细信息的展示与删除
  • Work@Alibaba 阿里巴巴的企业应用构建之路
  • 紧急通知:《观止-微软》请在经管柜购买!
  • 面试题:给你个id,去拿到name,多叉树遍历
  • 嵌入式文件系统
  • 使用 QuickBI 搭建酷炫可视化分析
  • 听说你叫Java(二)–Servlet请求
  • media数据库操作,可以进行增删改查,实现回收站,隐私照片功能 SharedPreferences存储地址:
  • Nginx实现动静分离
  • ​queue --- 一个同步的队列类​
  • ​RecSys 2022 | 面向人岗匹配的双向选择偏好建模
  • (+3)1.3敏捷宣言与敏捷过程的特点
  • (2015)JS ES6 必知的十个 特性
  • (22)C#传智:复习,多态虚方法抽象类接口,静态类,String与StringBuilder,集合泛型List与Dictionary,文件类,结构与类的区别
  • (js)循环条件满足时终止循环
  • (zhuan) 一些RL的文献(及笔记)
  • (仿QQ聊天消息列表加载)wp7 listbox 列表项逐一加载的一种实现方式,以及加入渐显动画...
  • (附源码)springboot社区居家养老互助服务管理平台 毕业设计 062027
  • (每日持续更新)信息系统项目管理(第四版)(高级项目管理)考试重点整理 第13章 项目资源管理(七)
  • (实战篇)如何缓存数据
  • (四)图像的%2线性拉伸
  • (五)IO流之ByteArrayInput/OutputStream
  • (一)使用IDEA创建Maven项目和Maven使用入门(配图详解)
  • (译)计算距离、方位和更多经纬度之间的点
  • (转)shell中括号的特殊用法 linux if多条件判断
  • (轉貼) 資訊相關科系畢業的學生,未來會是什麼樣子?(Misc)
  • .bat批处理(十一):替换字符串中包含百分号%的子串