二维数组和指针(包含交换二维数组行列)

有必要对a[i]的性质作进一步说明。a[i]从形式上看是a数组中的第i个元素。如果a是一维数组名,则a[i]代表a数组第i个元素所占的内存单元的内容。a[i]是有物理地址的,是占内存单元的。但如果a是二维数组,则a[i]是代表一维数组名。它只是一个地址(如同一维数组名只是一个指针常量一样。) a,a+i,a[i],*(a+i),*(a+i)+j,a[i]+j都是地址。 *(a[i]+j)和*(*(a+i)+j)是二维数组元素a[i][j]的值。
举例说明一下:
int a[3][4]={…………};
a,*a; 第0行首地址和0行0列元素地址
a[0],*(a+0); 第0行0列元素地址
&a[0],&a[0][0];第0行元素首地址和0行0列元素地址
a[1],a+1; 第1行0列元素地址和1行首地址
&a[1][0],*(a+1)+0; 1列0行元素地址
a[2],*(a+2);2行0列元素地址
&a[2],a+2;第2行元素首地址
a[1][0],*(*(a+1)+0);第1行0列元素的值。

⑴ 用指针表示二维数组元素。
  要用指针处理二维数组,首先要解决从存储的角度对二维数组的认识问题。我们知道,一个二维数组在计算机中存储时,是按照先行后列的顺序依次存储的,当把每一行看作一个整体,即视为一个大的数组元素时,这个存储的二维数组也就变成了一个一维数组了。而每个大数组元素对应二维数组的一行,我们就称之为行数组元素,显然每个行数组元素都是一个一维数组。因此,用两级数组的观点来看待二维数组时,一个M×N的二维数组a,可分解为图11-4所示的一维数组:
  行数组元素 数组元素
  二维数组a a[0] a[0][0] 数
  组
  a[0]
  a[0][1]
  ┇
  a[0][N-1]
  a[1] a[1][0] 数
  组
  a[1]
  a[1][1]
  ┇
  a[1][N-1]
  ┇ ┇ ┇
  a[M-1] a[M-1][0] 数
  组
  a[M-1]
  a[M-1][1]
  ┇
  a[M-1][N-1]
  图11-4 二维数组中的一维数组
  下面我们讨论指针和二维数组元素的对应关系,清楚了二者之间的关系,就能用指针处理二维数组了。
  设p是指向数组a的指针变量,若有:
  p=a[0];
  则p+j将指向a[0]数组中的元素a[0][j]。
  由于a[0]、a[1]┅a[M-1]等各个行数组依次连续存储,则对于a数组中的任一元素a[i][j],指针的一般形式如下:
  p+i*N+j
  元素a[i][j]相应的指针表示为:
  *( p+i*N+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]。数组a的分解情况如图11-5所示。
  数组a a[0] 10 20 30 40
  a[1] 50 60 70 80
  a[2] 90 91 92 93
  图11-5 数组分解举例
  若有:
  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赋值是错误的。这一点请读者务必注意。
  ⑵ 用二维数组名作地址表示数组元素。
  另外,由上述说明,我们还可以得到二维数组元素的一种表示方法:
  对于二维数组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 求二维数组元素的最大值。(补充例题,参考书例11-5)
  该问题只需对数组元素遍历,即可求解。因此,可以通过顺序移动数组指针的方法实现。
  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  if(*p>max)
  max=*p;
  printf("MAX=%d\n",max);
  }
  执行结果:
  MAX=88
  这个程序的主要算法都是在for语句中实现的:p是一个int型指针变量;p=a[0]是置数组的首元素地址为指针初值;max=*p将数组的首元素值a[0][0]作为最大值初值;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
  ⑶ 行数组指针
  在上面的说明中我们已经知道,二维数组名是指向行的,它不能对如下说明的指针变量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为行指针,如图11-6所示。
  p (*p)[0] (*p)[1] (*p)[2] (*p)[3]
  图11-6 行指针p的指向
  此时,可用如下方式对指针p赋值:
  p=a;
  赋值后p的指向如图11-7所示。
  p 10 11 12 13
  p+1 20 21 22 23
  p+2 30 31 32 33
  图11-7 行指针p在二维数组中的指向
  
  
  Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1346563

我自己写的交换二维数组行列方法:

#include <stdio.h>
#include <string.h>
void function(int pt[10][10]);
void function(int pt[10][10])
{
int i,j=0;
int temp;
for(i = 0;i<10;i++)
{
 for(j=i;j<10;j++)
 {
  temp = pt[i][j];
  pt[i][j]=pt[j][i];
  pt[j][i]=temp;
 }

}
}
int main(void){

  int i, j, a[10][10];

  for (i = 0;i < 10; i++) {
    for (j = 0;j < 10; j++)
  a[i][j] = 10*i + j;
  }
  function(a);
  for (i = 0;i < 10; i++) {
    for (j = 0;j < 10; j++)
  printf("%3d", a[i][j]);
    printf("\n");
  }
  return 0;
}


  • 4
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值