Chinaunix首页 | 论坛 | 博客
  • 博客访问: 381262
  • 博文数量: 67
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1741
  • 用 户 组: 普通用户
  • 注册时间: 2013-07-21 22:46
文章分类
文章存档

2014年(22)

2013年(45)

分类: C/C++

2014-01-02 17:42:59

大部分人,特别是初学者对于一些奇怪的数组表达式表示诧异。

     举个例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    
#include
int main(void)
{
int a[3];
for(int i = 0; i<3; ++i)
{
    *(a+i) = i+1;
}
//what is this ?! Are you kidding me ?!
//----------------------
printf("%d\n",*(a));
printf("%d\n",0[a+1]);
printf("%d\n",((*a)[a+1]));
return 0;
}

     恩,很复杂,很无聊,感觉这样来表达根本没有意义。我也承认,把故意把它复杂化了,目的是讲清楚一些有关数组与指针的关系。

     上面的程序,运行结果是把数组元素顺序输出,也就是分别输出1,2,3。

     先来看看数组的定义:int a[3];

     a 是数组名,相信大家都有过数组名 a 作为函数实参的经历,也就是把数组首元素地址 &a[0] 传给函数。这说明什么,说明数组名 a 一个指针,默认指向了数组的第一个元素 a[0]。

     那么 a 作为指针,*a 是什么也就清楚了,*a 可以说是数组第一个元素的引用,也就是说,

*a = a[0]。以此类推 *(a+1) = a[1]……

     明白这个之后,再来看看下面这个推导“公式”。

     *a = *(a+0) = a[0] = *(0+a) = 0[a];

     *(a+1) = a[1] = *(1+a) = 1[a];

     这些表达式都是对的,a[i] = i[a] 也是成立的。再看看下面的推导:

     *(a+1+1) = a[2] = *(1+a+1) = 1[a+1];

     所以,a[2] = 1[a+1] 成立。可以这样来想,(i)[a+j] = a[i+j];

     通过以上说明,对c语言数组与指针的关系可能更加清晰了。很多时候,我们会自己另外定义指针来指向数组:


1
2
3
4
5
6
    
int *p;
int a[3];
p = a; //从这里可以看出,a 就是一个指针
//有些人这样定义也对
p = &a[0];
p = &(*(a));

     通过自己另外定义的指针来对数组进行操作,然而低调的数组名 a ,却淡然于世外,被人遗忘。

     所以,回头看看一开始的那个程序,一切也就明白了,核心就是:数组名就是一个指针,默认指向了数组的首元素。所以,你对数组名的任何指针式的操作都是合法的。


     上面是一维数组的操作,下面来说说二维数组。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    
#include
int main(void)
{
int a[2][2];
a[0][0] = 1;
a[0][1] = 2;
a[1][0] = 3;
a[1][1] = 4;
//what is this ?! Are you kidding me ?!
//----------------------
printf("%d\n",0[*(a)]);
printf("%d\n",*(*(a)+1));
printf("%d\n",3[*(a)-1]);
printf("%d\n",1[*(a)+2]);
return 0;
}

    呵呵,这段代码也挺让人抓狂的,没人会这么做,这么做的不是优秀的程序员。我还是那句话,夸张化来说明一些道理。不这么写,但是一定要明白为什么可以这么写,这是我的一点追求。

    如果上面一维数组的讲解清楚了,那么二维数组其实不难理解。

    先来看看定义:

    int a[2][3];

    代表什么意思?可以有很多理解,有些人觉得这可以看成是一个类似坐标的矩阵,比如把第一个[]里面的想成是x轴,第二个[]里面是y轴,所以这样对a[1][2]就很容易理解,这样理解是可以的。

    有意思的是,它不过就是一维数组里面有个一维数组而已。拿a[2][3]举例,也就是说,首先,数组名是 a ,它是一个一维数组a[2],这个一维数组的每一个元素放着什么呢?放着3个元素,把表达式就写成a[2][3]。跟一维数组一样,数组名 a 是指针,默认指向a[0][i],但是问题来了,因为a[0][i]当中的内存块里面有三个int型的分别是a[0][0],a[0][1],a[1][2],究竟指向哪个呢?哪个都不指向,就只是指向a[0][i]而已,那么指向a[0][0]的指针在哪?在这:*a 。  *a 就是指向a[0][0]的指针,明白这种关系吗?这里有个双重指针。我结合一维数组来解释一下:

    一维数组中,a 是指针指向首元素,那么有等式【1】 *a = a[0];

    二维数组中,a 是指针指向首元素a[0][i],那么利用上面的等式【1】,a[0][i]可以推导写出这样的等式:a[0][i] = *a[i],*a 可以看成是数组名,所以,*a 就是指向 a[0][0] 的指针,这样就清楚多了,呼~

    所以,理清楚这个关系,输出**a,也就是输出a[0][0]了,*(*a+1),当然就是a[0][1]。

    所以,对于三维数组也清楚了吧,***a 就是 a[0][0][0],多维数组以此类推……

    对于这样的表达式:0[*(a)],也能理解了,推导:(见笑,笔者对逻辑步骤比较感兴趣)

    0[*(a)] = *(a)[0] = *a[0] = a[0][0];

    恩,对c语言的数组与指针说得有点复杂,但这些确实很重要,平时编程可以不这么写,但是一定要懂得里面的原理,这样的好处不是让自己能运用,而是让自己不会运用错误。(指针操作错误可能引发很大的麻烦)

    水平有限,有些包含不到,有些分析欠佳的,还请谅解。
阅读(1348) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~