指针和二维数组

指针与二维数组也有三种表示形式。

1. 第一种形式:用指向二维数组元素的指针变量

#include<stdio.h>
int main()
{
	int i,*p,n,m;
	scanf("%d%d",&n,&m);
	int a[n][m];
	for(p=a[0];p<a[0]+n*m;p++)
	{
		scanf("%d",p); //  p+i
		printf("%d\t",*p); //  *(p+i)
	}
	return 0;
}
因为二维数组a中的n*m个元素在内存中是依序存放的,p=a[0];是把p指向了二维数组的起始地址,也即这n*m个元素的初始地址,然后采用一维数组中的指针变量法来访问数组a中的各个元素。

当然,也可以采用一维数组中的首地址法来访问数组中的各个元素。

#include<stdio.h>
int main()
{
	int i,*p,n,m;
	scanf("%d%d",&n,&m);
	int a[n][m];
	for(p=a[0],i=0;i<n*m;i++)
	{
		scanf("%d",p+i);
		printf("%d\t",*(p+i));
	}
	return 0;
}

通过首地址加偏移量的方法即可访问二维数组a中的各个元素。
有同学会说,老师,能否用指针操作一维数组中的下标法来操作二维数组呢?问题没有那么简单额。

2. 第二种形式:指针数组

 对于数组a[2][3]来说,数组a包含了两行a[0]和a[1],而每行又包含了3个元素,因而a[0]和a[1]如同一维数组,因而我们可以定义一个指针数组,用a[0]和a[1]对该指针数组进行初始化。int *p[2]={a[0],a[1]}; p是数组名,数组中有两个元素,两个元素的类型为int*。

`

#include<stdio.h>
int main()
{
	int i,j,a[2][3];
	int *p[2]={a[0],a[1]};
	for(i=0;i<2;i++)
		for(j=0;j<3;j++)
		{
			scanf("%d",p[i]+j);   // &p[i][j]
			printf("%d\t",*(p[i]+j)); //p[i][j]
		}
	return 0;
}

这样定义之后,p的地位和数组a的地位相同,因而凡是可以用a[i][j]的地方,均可以用p[i][j]来描述。

比较有意思的是,由于p[i]可以用*(p+i)来描述,因而p[i]+j可以改写为:*(p+i)+j,而*(p[i]+j)则可以描述为:*(*(p+i)+j)。

3. 第三种形式:指向一维数组的指针变量,相当于行指针

先调试下面的代码,看看会有什么情况发生?

#include<stdio.h>
int main()
{
	int a[2][3],i,j;
	int **p;  //改为int *p试试看??
	p=a;
	for(i=0;i<2;i++)
		for(j=0;j<3;j++)
		{
			scanf("%d",&p[i][j]);
			printf("%d\t",p[i][j]);
		}
	return 0;
}

调试:如果我们定义:int **p;

当系统编译到语句p=a;时会发出警告:
E:\VC6.0完整绿色版\VC6.0完整绿色版\Common\MSDev98\Bin\a.c(8) : warning C4047: ‘=’ : 'int ** ’ differs in levels of indirection from ‘int (*)[3]’
而在你们深爱的codeBlocks中,如果我们定义:int **p;
当系统编译到语句p=a;时会给出警告:
C:\Users\Administrator\Documents\Untitled1.c|6|warning: assignment from incompatible pointer type
我们通常会对警告置之不理,仍坚持输入数据1 2 3 4 5 6,当敲下回车时,会弹出如下图所示的对话框。这个对话框出现就意味着对内存的操作出现了问题。
在这里插入图片描述

从VC++6.0的警告中,可知int a[2][3]中,a的类型为int (*a)[3],所以为了和它类型相同,地位相同,需要把指针变量定义为:int (*p)[3]; 如此这般,才可以把p=a;对p的操作才可以如同对a的操作那般。那么,如何来理解int (*a)[3]呢????

我们先来看一个程序:

#include<stdio.h>
int main()
{
	int a[2][3]={0};
	printf("%x\n",a);
	printf("%x\n",a+1);
	printf("%x\n",a[1]);
	return 0;
}

在这里插入图片描述

从运行结果可以看出,a+1指的是a[1]这一行的首地址。由于二维数组名是地址,地址也就意味着是指针,但该指针每加上1就移动了一行,可见a是一个指向包含3个元素的指针,需要定义一个也指向包含3个元素的指针变量,然后把a赋给该指针变量,随后就可以通过该指针变量对a中的元素进行存取。
正确程序如下:

#include<stdio.h>
int main()
{
	int a[2][3],i,j;
	int (*p)[3];
	p=a;
	for(i=0;i<2;i++)
		for(j=0;j<3;j++)
		{
			scanf("%d",&p[i][j]);
			printf("%d\t",p[i][j]);
		}
	return 0;
}

综上所述,采用指针对二维数组来进行操作,一共有3中描述形式:

     int a[2][3];                                                   int a[2][3];
	 int *p[2]={a[0],a[1]};                                         int (*p)[3]=a;
   a[i][j]的地址(6种形式是等价的)//  i是行,j是列
	&a[i][j],a[i]+j,*(a+i)+j
	&p[i][j],p[i]+j,*(p+i)+j

	a[i][j]的取值(6种形式是等价的):
	a[i][j],*(a[i]+j),*(*(a+i)+j)
	p[i][j],*(p[i]+j),*(*(p+i)+j)

4. 扩展知识

其实,二维数组中的元素在内存中的存放是按序存放的,它们离首地址的偏移量与它们的行标和下标有关系。分析下面程序:

#include<stdio.h>
int main()
{
	int a[2][3]={1,2,3,4,5,6},i,j;
	int *p=(int*)a;
	for(i=0;i<2;i++)
		for(j=0;j<3;j++)
		{
			printf("%d\t",*(p+i*3+j));
		}
	return 0;
}

思考:p+i*3+j是什么意思呢?
其实,i*3+j是元素a[i][j]与数组首地址的偏移量。首地址存入指针变量p中,p+偏移量自然是a[i][j]的地址。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值