C语言程序设计第章.pptx
第十章二维数组和指针2009.8 朱立华 俞琼 王立柱1第1页/共29页2009.8 2009.8 朱立华朱立华 俞琼俞琼 王立柱王立柱2 2内容提要与二维数组相关的各类指针 二维数组的初始化及元素访问方式二维数组的定义,其中涉及的3种类型本章介绍二维数组的有关知识动态二维数组空间的申请与释放(选讲)内容提要二级指针列指针行指针一维指针数组利用二级指针申请动态二维数组空间如何依次释放申请的所有动态空间第2页/共29页2009.8 2009.8 朱立华朱立华 俞琼俞琼 王立柱王立柱3 3重点难点提示重点难点提示二维数组的定义与使用二维数组与行指针二维数组与列指针动态演动态演示示动态演动态演示示二维数组与指针数组动态演动态演示示动态演动态演示示第3页/共29页2009.8 朱立华 俞琼 王立柱4二维数组的定义哪里需要二维数组?类型相同的一组数,如果在序列中只受一种序号标明其在整个序列中的顺序,用一维数组,例如:1门课各个同学的成绩 类型相同的一组数,如果在序列中需要用两种序号标明其在整个序列中的顺序,则要用二维数组,例如:3门课各个同学的成绩矩阵问题强调元素所在的行、列位置,必须用二维数组二维数组的定义形式:类型标识符 数组名整型常量表达式1 整型常量表达式2;例:int a43;/定义4行3列的整型二维数组,数组名为a 二维数组的元素类型二维数组名是一个用户自定义标识符指明二维数组的行数指明二维数组的列数第4页/共29页2009.8 朱立华 俞琼 王立柱5二维数组的定义二维数组的实质分析:二维数组是一维数组的一维数组(递归定义)例:int a43;(1)这里,a是二维数组名,也可以理解成是一维数组名a,它有4个元素,分别为a0、a1、a2、a3(2)a的4个元素不是普通的变量,而是都分别是一维数组,称为行一维数组,每一个都有3个int型元素,例:a0的3个元素为:a00、a01、a02(3)因此,二维数组a中共有12(4*3)个int型的元素:a00、a01、a02a10、a11、a12a20、a21、a22a30、a31、a32它们4个称为行一维数组第1个下标称为行下标第2个下标称为列下标这12个元素称为二维数组元素行数列数第5页/共29页2009.8 朱立华 俞琼 王立柱6二维数组的定义二维数组定义中含有3种类型:例:int a43;(1)int 43:是二维数组a的类型标识(2)int 3:是行一维数组a0a3的类型标识,也是二维数组的基类型(3)int:是二维数组元素a00a32的类型,也是行一维数组的基类型二维数组定义中的常量与变量:例:int a43;(1)二维数组a和行一维数组a0a3均为指针常量(2)二维数组元素a00a32是int型的变量第6页/共29页2009.8 朱立华 俞琼 王立柱7二维数组的初始化二维数组在定义的同时可为其元素赋值,称为初始化,原则:行从左到右依次,每行中列从左到右依次(1)逐行初始化:int a43=1,2,3,4,5,6,7,8,9,10,11,12;(2)行数可以缺省,列数不能省,自动算行:int a 3=1,2,3,4,5,6,7,8,9,10,11,12;(3)不分行,用类似一维数组的方式初始化:int a43=1,2,3,4,5,6,7,8,9,10,11,12;(4)初始化数据不足,系统用0补充:int a43=1,2,4,5,7,8,9,10,11,12;(5)最简单的初始化:int a43=0;每行单独用一对大括号括起共有两层大括号只有一层大括号等效于int a43=1,2,0,4,5,0,7,8,9,10,11,12;第1个元素初始化为0,其余未初始化的元素值自动为0行数计算出来为4,不初始化时不能缺少行数第7页/共29页2009.8 朱立华 俞琼 王立柱8二维数组的初始化错误的初始化示例:(1)未遵守行从左至右依次初始化原则:int a43=,4,5,6,7,8,9,10,11,12;(2)同一行中未遵守列从左至右依次初始化原则:int a43=1,3,4,5,6,7,8,9,10,11,12;int a43=1,2,3,5,6,7,8,9,10,11,12;(3)不分行,用类似一维数组的方式初始化,未按顺序:int a43=1,2,4,6,7,8,9,10,11,12;(4)省略列号:int a4=1,2,3,4,5,6,7,8,9,10,11,12;中间缺少两个元素,不符合从左到右依次的原则第1行没有初始化,后面行就不能初始化第1行第2列没有初始化,第3列就不能初始化第2行第1列没有初始化,第2、3列就不能初始化二维数组初始化中列号一定不能省略第8页/共29页2009.8 朱立华 俞琼 王立柱9二维数组元素的访问a00a00 a01a01 a02a02 a10a10 a11a11 a12a12 a20a20 a21a21 a22a22 a30a30 a31a31 a320i 30 j 2a0a1a2a3n二维数组元素可随机访问,因为每个元素地址可计算Loc(aij)=a+(i*m+j)*sizeof(二维数组元素类型)n数组元素的表示形式:例:int a43;(1)最常用的是下标(行、列)法:aij(2)间接引用法与下标法结合:*(ai+j)、(*(a+i))j(3)间接引用法:*(*(a+i)+j)n二维数组元素在内存中的存储形式:先行后列依次行下标列数列下标第9页/共29页2009.8 朱立华 俞琼 王立柱10二维数组元素的访问一般要对所有的数组元素执行同样的操作,与一维数组类似,用循环结构控制,二维数组需用两层循环例:int a43,n=1,i,j;for(i=0;i4;i+)for(j=0;j3;j+)ai j=n+;程序10.1 将如下所示的矩阵存入二维数组,然后照原样输出,最后按转置形式输出。算法提示:转置输出不需要另外定义二维数组,只是在控制循环时先控制列下标再控制行下标动动态态演示演示过过程程第10页/共29页2009.8 朱立华 俞琼 王立柱11二维数组与一维数组二维数组名是二维数组指针常量如果按照递归的概念,它也是特殊的一维数组指针 例:int a43;(1)指针a的基类型为int3,a指向a0,即a=&a0,因此a+i指向ai,即:a+i=&ai,a+i或&ai称为行指针地址计算公式为:a+i=a+i*sizeof(二维数组元素类型*列数)(2)指针ai的基类型为int,ai指向元素ai0,即ai=&ai0,因此ai+j指向元素ai j,即:ai+j=&ai j,ai、*(a+i)、ai+j或&ai j称为列指针或一维指针地址计算公式为:ai+j=ai+j*sizeof(二维数组元素类型)0i3第11页/共29页2009.8 朱立华 俞琼 王立柱12二维数组与一维数组一级指针也称为列指针或一维指针,这是一级指针在针对行指针或二维数组指针时的称谓程序10.2 二维数组行指针和列指针的区别提示:a与a0的值虽然相等,但基类型不同,因此注意比较a+1与a0+1的不同值(在VC+下演示程序)结论1:一个m行n列的二维数组可以作为长度为m*n的一维数组,二者在内存中的存储顺序一致程序10.3 把二维数组当作一维数组输出算法提示:用一层循环而不是二层循环控制,注意换行条件动动态态演示演示过过程程第12页/共29页2009.8 朱立华 俞琼 王立柱13二维数组与一维数组结论2:一个长度为n的一维数组可以作为1行n列二维数组例如:double d5=1,2,3,4,5;这里指针d的基类型为double,而指针(&d)的基类型是double5(参看5.2.3节),相当于1行5列二维双浮点型数组指针 程序10.4 一维数组可以看作行数为1的二维数组。算法提示:(&一维数组名)相当于二维数组名动动态态演示演示过过程程注意:这里的括号不能少第13页/共29页2009.8 朱立华 俞琼 王立柱14二维数组名的双重含义(选讲)含义一:整个二维数组变量空间的名称,在执行字节计算sizeof和取址运算&时,a就是整个二维数组空间标识符,即二维数组变量的名称 例:int a43,则a的类型为int 43sizeof(a)的值是48,&a+1比&a大48 含义二:行一维数组指针,称为二维数组指针,也称行指针,因为数组变量不能通过其名称直接引用数组元素,因此二维数组名称“退化”了,大部分时候都是这一含义。第14页/共29页2009.8 朱立华 俞琼 王立柱15二维数组与行指针 二维数组要传址,可以传递二维数组指针二维数组指针的基类型由二维数组元素类型和列数两部分联合表示因此,接受二维数组指针的指针变量,其基类型也应该由两部分联合表示,而且对应的部分完全一致,这样的指针变量称为行指针变量 例:int(*p)3;/行指针变量pint a43=1,2,3,4,5,6,7,8,9,10,11,12;p=a;/将二维数组指针赋值给行指针变量此时行指针变量p等价于二维数组指针a,有以下等价式:p+i=a+i pi=aipi j=ai j 对应于二维数组元素类型对应于二维数组的列数还可以:p=a+i或p=&ai,保证p得到的是行指针都是正确的此处的括号一定要有!第15页/共29页2009.8 朱立华 俞琼 王立柱16二维数组与行指针 程序10.5 将给定矩阵按转置形式输出。本程序与程序10.2功能类似,但作了简化,二维数组元素初始化给定,不需要输出原始矩阵。本程序用Display函数实现矩阵转置输出重点理解如何用行指针变量作为形参接受二维数组实参。注意:此题的函数原型可以有以下三种等效表示:(1)void Display(int(*pa)3,int row);(2)void Display(int pa3,int row);(3)void Display(int pa43,int row);后两种本质上就是第一种形式,且后两种形式只能出现在形参表中,不能作为行指针变量的定义(或声明)形式 动动态态演示演示过过程程第16页/共29页2009.8 朱立华 俞琼 王立柱17二维数组与列指针一个m行n列二维数组,可以看作是长度为m*n的一维数组,因此二维数组可以传址给列指针例:int a43;则a0(或*a或&a00)是指向第1个二维数组元素a00的指针常量,它等价于长度为12的一维整型数组指针,该一维数组的12个元素依次为:a00、a01a011此时存在等式:a0i*3+j=ai j 因此,可以通过定义一个列指针(一级指针)变量来接受a0的值,例如:int*p=a0;则 pi*3+j=ai j 这样,二维数组也可以通过将其起始列地址传给一个一级指针变量来访问所有的元素行下标列数列下标第17页/共29页2009.8 朱立华 俞琼 王立柱18二维数组与列指针程序10.6 寻找矩阵中的马鞍点。一个矩阵中的元素,若在它所在的行中最小,在它所在的列中最大,则称为马鞍点。求一个n*m阶矩阵的所有马鞍点。算法思想:用一个 n行m列二维数组a来存储矩阵,一个长度为n的一维数组min存储每行中的最小元素,一个长度为m的一维数组max存储每列中的最大元素。寻找马鞍点的具体方法是:用行控制外层循环,在i行其行中最小元素为min i,在行固定的情况下,用列控制内层循环,用每一列的最大元素值max j与当前行的mini去比较,如果二者相等,则说明一个二维数组元素ai j就是马鞍点。显然,一个矩阵中可能不止一个马鞍点,也有可能没有马鞍点。马鞍点元素加括号输出。动动态态演示演示过过程程第18页/共29页2009.8 朱立华 俞琼 王立柱19一维指针数组与二级指针所谓一维指针数组,就是数组元素为一级指针变量的一维数组。例:char*a5;a是长度为5的一维字符型指针数组,a是指针常量,一维数组元素a0、a1、a2、a3、a4都是一级字符型指针变量,它们各自可以指向一维字符数组,特别是字符串对每个元素(一级指针变量)都可以赋值:a0=File;a1=Edit;a2=Compile;a3=Run;a4=Tools;也可以在定义一维指针数组时进行初始化,如普通一维数组char*a5=File,Edit,Compile,Run,Tools;或char*a=File,Edit,Compile,Run,Tools;注意:此处不能加括号:而char(*a)5是1个行指针定义第19页/共29页2009.8 朱立华 俞琼 王立柱20一维指针数组与二级指针一维指针数组名可以赋值给何种类型的变量?回顾:一级指针变量与一维数组的关系Type arraysize;/数组array的元素类型为Type,即数组指针的基类型为TypeType*p;/指针变量p的基类型为Type因此:p=array;/指针变量p指向数组array 如果有指针数组定义:char*a5,则数组a的元素类型是char*,即数组指针常量a的基类型是char*,则接受a值的指针变量的基类型也应该是char*,故该指针变量类型是char*,称为(字符型)指针的指针,也称二级指针 于是:char*pa=a;这时,pai与ai等效,都是指向某一个字符串的首地址pa为二级指针变量a为一维指针数组名第20页/共29页2009.8 朱立华 俞琼 王立柱21一维指针数组与二级指针程序10.7 主函数中定义指针数组处理多个字符串,函数以指针的指针为形参输出所有字符串的值。输出函数原型:void Display(char*pa,int n);另一种形式:void Display(char*pa,int n);二级指针、一级指针与普通变量的关系:例:char ch=A;/定义一个普通字符型变量char*p=&ch;/一级指针变量p指向了变量chchar*q=&p;/二级指针变量q指向了一级指针p则对字符值的访问形式有等效的3种形式:ch、*p、*q,如下图所示动动态态演示演示过过程程这种形式的形参本质上就是char*paq qp pchch0 x12ff78 0 x12ff78 0 x12ff7c 0 x12ff7c A A&p&p&ch&ch、*q q*p p、*q q第21页/共29页2009.8 朱立华 俞琼 王立柱22一维指针数组与二维数组 一维指针数组是元素为一级指针变量的一维数组。每一个一级指针变量可以分别指向长度不同、且彼此空间不相邻的一维数组。二维数组是元素为一级指针常量的一维数组。每一个指针常量分别指向长度相同、彼此空间相邻的一维数组,例:char cColor47=“white”,”red”,”orange”,”pink”;char*pColor4=“white”,”red”,”orange”,”pink”;cColor是二维数组,其元素为cColor0cColor3,它们都是长度为7的字符型一维数组,且在内存中连续存放pColor是一维指针数组,其元素为pColor0pColor3,它们都是一级指针变量,可以指向各独立存放的串首地址第22页/共29页2009.8 朱立华 俞琼 王立柱23一维指针数组与二维数组w wh hi it te e 00r re ed d00o or ra an ng ge e00p pi in nk k00cColorcColorcColor0cColor0cColor1cColor1cColor2cColor2cColor3cColor3pColorpColorpColor0pColor0pColor1pColor1pColor2pColor2pColor3pColor3white0white0red0red0orange0orange0pink0pink0这这4 4个个字符串字符串长度相长度相等地址等地址相邻相邻这这4 4个字符串个字符串长度不相等长度不相等地址不一定地址不一定相邻相邻多个字符串的处理,既可以用二维字符数组,又可以用一维指针数组,后者是更常用的处理方式。第23页/共29页2009.8 朱立华 俞琼 王立柱24一维指针数组与二维数组 指针数组的每一个元素作为指针变量,可以指向二维数组的行数组,当然,要保证基类型的一致性。前面的例示中,可以用以下循环实现赋值:for(i=0;i4;i+)pColori=cColori;程序10.8 指针数组和二维数组。用二维整型数组存储一个矩阵,通过一维指针数组输出矩阵指针数组的元素是指针变量,不仅可以指向静态数组也可以指向动态数组 例:int*p4,i;for(i=0;i4;i+)pi=(int*)malloc(3*sizeof(int);动动态态演示演示过过程程第24页/共29页2009.8 朱立华 俞琼 王立柱25二维动态空间的申请与释放(选讲)一级指针可以申请动态一维数组空间,同理,二级指针可以申请动态二维数组空间,需要分两步走:用二级指针申请动态二维数组的方法是:(1)首先用二级指针申请一维指针数组空间,指针数组的长度就是动态二维数组的行数;(2)接着用这些一级指针变量分别申请动态一维数组空间,其元素个数就是动态二维数组的列数。释放动态二维数组空间的方法是(与申请顺序相反):(1)用一层循环首先释放所有由一级指针所申请的动态空间先释放二维数组元素空间(2)再直接通过二级指针变量释放一维指针数组空间后释放一维指针数组的空间第25页/共29页2009.8 朱立华 俞琼 王立柱26array00 array01 array02 二维动态空间的申请与释放(选讲)程序10.9 通过二级指针变量array申请了row行col列的动态二维数组空间,二维数组的元素为099之间的随机数。最后以矩阵形式输出该动态二维数组。关键语句:int*array,row,col;array=(int*)malloc(row*sizeof(int*);for(i=0;irow;i+)arrayi=(int*)malloc(col*sizeof(int);现在:arrayi j就与静态数组元素一样进行访问了动动态态演示演示过过程程申请一维指针数组空间,该数组含row个元素再用这row个一级指针分别申请col个二维数组元素空间arrayarrayarray0array0array1array1array10 array11 array12若row=2,一维指针数组空间,该数组含2个一级指针元素若col=3,这是array0申请的一维整型数组,该数组含3个int型元素若col=3,这是array1申请的一维整型数组,该数组含3个int型元素这6个便是用二级指针申请的动态二维数组元素第26页/共29页2009.8 朱立华 俞琼 王立柱27二维(数组)指针和一维(数组)指针的相互转化 下表总结了第5章所讲的一级指针与一维数组、本章所讲的行列指针与二维数组,指针数组及指针的指针之间的关系。指针名称指针名称指针定义举例指针定义举例数组定义举例数组定义举例可进行的赋值可进行的赋值基类型基类型一级指针一级指针(列指针列指针)int*p;int a10;int m=2;int a43;p=a;p=a+i;p=&ai;p=&m;p=&aij;p=ai;p=*(a+i);int行指针行指针int(*p)3;int a43;int arr3;p=a;p=a+i;p=&ai;p=&arr;int3二级指针二级指针int*p;int*a3;p=a;p=a+i;p=&ai;int*指针数组指针数组int*p4;char*s4;int a43;char b47=”white”,”red”,yellow”,”green”;pi=ai;Si=bi;int*char*第27页/共29页2009.8 朱立华 俞琼 王立柱28二维(数组)指针和一维(数组)指针的相互转化 二维数组中的行列指针及相互转化例:int a43;则行指针有:a、a+i、&ai 列指针有:*a、*(a+i)、ai、ai+j、&aij 二 维 数 组 元 素 的 表 示 有:aij、(*(a+i))j、*(ai+j)、*(*(a+i)+j)转化方法:行变列,加*号;列变行,取址&这种转化方法与一维数组元素与其地址的相互转化规则一样!(地址到值,加*号;值到地址,取址&)例:int a4;元素的地址有:a、a+i、&ai元素值的表示方法有:*a、*(a+i)、ai地址值是:&ai0地址值是:&aij第28页/共29页2009.8 朱立华 俞琼 王立柱29感谢您的欣赏!第29页/共29页