`
womendu
  • 浏览: 1474751 次
  • 性别: Icon_minigender_2
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

多维数组和指针

阅读更多

声明:1. 文章如有不妥的地方,请您指正,谢谢.
2.另外文中有些细节可能引用您的内容却未给出参考,请原谅我的疏忽,你的共享我不会忘记.
3. Email:lizhiguo0532@163.com 李枝果/lizgo
4.转载请保留该部分信息

二维数组在多维数组中算是简单的了,但是如果二维数组不清楚,就很难理解多维数组是怎么个概念了。
在这里还是要提到一个重要的c语言关键字:tepydef,可以说,任何复杂的类型申明都可以用typedef
来拆解成简单易懂的申明。
定义多维数组,以四维数组int a[5][4][3][2]定义为例,可以这样
typedef int ONE[2];
typedef ONE TWO[3];
typedef TWO THREE[4];
typedef THREE FOUR[5];
到此已经将类型申明完成,下面就可以用FOUR来定义int a[][4][3][2]这种结构的四维数组了
FOUR a;<--------->int a[5][4][3][2];
不过这样声明之后定义数组就比较局限了,我们做一下如下改动:
将typedef THREE FOUR[5];换成typedef THREE FOUR;之后就可以定义了:
FOUR a[5];
FOUR b[10];
...
那a这个多维数组的结构是怎么样的呢?
int a[5][4][3][2];
首先先不要管前面的int 关键字,从数组名a开始往右看,遇到第一个[5],说明a是一个具有5个元素的数组,那里面的元素是什么类型呢?
暂时先不管,再往右看,右是一个[4],说明前面具有5个元素的数组的每个元素又是一个具有4个元素的数组,那具有4个元素的数组的每个元素是什么
类型呢?还是先不管,继续往右看,哦,右遇到了一个[3],这说明前面具有4个元素的数组的每个元素又是一个具有3个元素的数组,那具有3个元素的数组
的每一个元素又是什么类型呢?还是不管,继续往右看,又遇到了[2],这说明具有3个元素的数组的每个元素又是一个具有2个元素的数组,那这个具有2个
元素的数组的每个元素又是什么类型呢?到这个时候再朝往看已经找不到[]了,这个时候就看看前面的类型修饰符是什么,这里是int ,这个就说明具有2个
元素的数组的每个元素都是int型数据。
上面的一大段话着实让人看来很晕,所以简
言之,就是利用递归的思想取看。下面看看这个多维数组初始化的时候的情况,以加深理解:
int a[5][4][3][2]={{},{},{},{},{}};//a是个数组,里面右5个元素
={{{},{},{},{}},{...},{...},{...},{...}};//5元素数组的每一个元素又是具有4个元素的数组 ,后面四个{...}和第一个{{},{},{},{}}一样
={{{{},{},{}},{...},{...},{...}},{...},{...},{...},{...}};//4元素数组的每个元素又是具有3个元素的数组
={{{{{},{}},{...},{...}},{...},{...},{...}},{...},{...},{...},{...}};//3元素数组的每个元素又是具有2个元素的数组
={{{{{1,2},{3,4}},{...},{...}},{...},{...},{...}},{...},{...},{...},{...}};//2元素数组的每个元素是int数据

二维数组
比如要定义一个int b[4][3];这个数组,当然你可以在程序中这样写,另外也可以利用typedef来简化类型声明。
typedef int A[3];//A 为具有3个元素的数组类型
A b[4];//b为具有四个元素的数组,其中每个元素的类型是A,即每个元素又是一个具有3个int型数据的数组

A c;//相当与int c[3];
A *p=&c;//p是一个数组指针,具体的说是具有3个int型数据的数组指针变量,这是上一篇文章里讨论一维数组时提及的

这里重提两句关于数组名的两句重要的话:数组名的内容是其首元素的首地址;数组名的类型是其元素类型的指针类型。另外数组名的基类型就是数组元素的类型
b[0][0] 类型:int 基类型:无
&b[0][0] 类型:int * 基类型:int
b[0] 类型:int * 基类型:int
&b[0] 类型:int (* )[3] 基类型:int [3]
b 类型:int (* )[3] 基类型:int [3]
&b 类型:int (* )[4][3] 基类型:int [4][3]

1.利用指针数组访问b
int *p[4];//[]先于*与p结合,说明p是一个具有4个元素的数组,但是每个元素又是一个int指针变量,可以这么来看,假设有个变量叫p[0],int p[0],
//(和int a;没什么本质差别,只是名字变了而已,如果int *a;那a就是一个int指针了),同理int *p[0],那p[0]也是一个int指针了。
那定义来一个int指针数组,我们怎么利用他来访问二维数组呢?
要知道在二维数组里面b[4][3],b[0],...,b[3]都表示3int元素的一维数组名,这些一维数组名的类型都是int *,在语言中类型(基类型)相同时,赋值
运算是合法的
有以下循环来初始化我们的int指针数组:
for(int i=0;i<4;i++)
p[i]=b[i];
//b[i]是一维数组名,是地址常量,不能出现在=号的左边,同时它们的值也不能改变
这样我们就可以通过p来引用b数组的元素:i是a的游标,j是a每个元素(一位数组)的游标
*(p[i]+j)<------>*(b[i]+j)
*(*(p+i)+j)<---->*(*(b+i)+j)
(*(p+i))[j]<---->(*(b+i))[j]
p[i][j]<------->b[i][j]

这里需要注意一点的是:p=b;这样是不合法的,因为p和b的类型不一样。b的类型是int (* )[3],而p的类型是int * [4]或者int **(int指针的指针类型)
这里我们可以定义一个int二级指针来指向p数组
int **pp;
pp=p;
这样就可以用pp来访问b数组了。另外还要注意的是数组名不能被修改,也就是不能参与指针运算。pp,p[i]可以参与指针运算。

2.利用数组指针访问b
int (*pa)[3];//pa首先是一个指针,这个指针指向的类型(基类型)是具有3个int元素的数组
pa的类型是int (* )[3],恰好与b的类型相同,所以
pa=b;是合法的赋值表达式。
我们可以用下面的方法来引用二维数组b
*(pa[i]+j)<------>*(b[i]+j)
*(*(pa+i)+j)<---->*(*(b+i)+j)
(*(pa+i))[j]<---->(*(b+i))[j]
pa[i][j]<------->b[i][j]
只是pa的内容可以改变,而b的内容不能变。

3.二维数组名和指针数组在函数传参时的实质性问题
这里需要提到的一点是,在c语言中,函数之间不能传递数组,但是可以传递结构体变量。所以在某些地方实在避免不了函数件传数组的话,就可以利用
结构体来进行封装
另外,在函数的形参列表里面,无论出现什么形式的数组声明,在最后进入函数体内部的时候都会退化成指针

二维数组名作为实参传递给函数时,函数的形参列表可以是以下形式:
fun(int (*a)[N]);
fun(int a[][N]);
fun(int a[M][N]);
指针数组名作为实参传递给函数时,函数的形参列表可以是以下形式:
fun(int *a[M]);
fun(int *a[]);
fun(int **a);
实例
利用数组指针数组访问一个二维数组,求出二维数组所有元素的和

#include <stdio.h>//a[4][3]

typedef int (*array_p)[3];
typedef array_p (pointer[4]);
//或者
typedef int (array)[3];
typedef array *(pointer_a[4]);

int a[4][3];

int main(int argc,char *argv[])
{
int i,j;
int sum=0;
int (*p[4])[3];

array_p ap[4];
pointer po;
pointer_a pa;


for(i=0;i<4;i++)
for(j=0;j<3;j++)
scanf("%d",&a[i][j]);

for(i=0;i<4;i++)
p[i]=&a[i];//ap[i]的类型是int (* )[3],&a[i]的类型也是int (* )[3]
//将此处的p换成po或者pa或者ap类型是一样的

for(i=0;i<4;i++)
for(j=0;j<3;j++)
sum+=*((*p[i])+j);

printf("%d\n",sum);
return 0;
}

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics