C语言指针和数组详解

      常常在BBS上看到有人问指针和数组的问题。我曾经也很迷惑,现在,我谈谈我对指针和数组的理解。欢迎批评指正讨论。

      1:定义数组

            int a[5];

            上一句定义了一个数组,名字叫a,它有5个元素,每个元素是int类型。换句话说,a是一个int [5]型的数组。int [5]表示的是类型,只不过是个复合类型,本质上,和int, float,double没有区别,都是类型。

      2:数组的操作。

            2.1:sizeof操作。

                        像1中的数组a,sizeof(a)的值也就是sizeof(int [5])的值,也就是5*sizeof(int)的值。

            2.2:加、减、赋值。

                        当一个数组参与加、减和赋值运算的时候,它首先被转换(converted to)成指向首元素的指针。

                        a+0是什么?这里数组a要做加法,所以,它首先被转换成指向首元素的指针。然后再加0。
                        同理,a-0的操作过程是:a首先转换成指向首元素的指针,再减0。

                        int *p = a;合法吗?合法。数组a在赋值运算的时候,首先a转换成指向首元素的指针,然后再赋值给p。

                        a+0,a-0和a,这三者有什么区别?a+0的类型是int *,a-0的类型是int *,a的类型是int [5],也就是说类型有同。但它们的值是相同的,都是数组a首元素的地址。

            2.3 下标运算符[]

                        大家都知道,要访问数组a的首元素,用a[0]就可以了。访问第二个元素,用a[1]就可以了。

                        
那么,[]究竟是什么?表达式 E1[E2] 等同于表达式 *((E1)+(E2)),等同于*((E2)+(E1)),等同于E2[E1].

                        所以a[0]等同于*((a)+(0))即*(a+0)。a+0是指向首元素的指针,那么*(a+0)就是首元素了。同理 a+1是指向第二个元素的指针,*(a+1)也就是第二个元素了。

            2.4 取地址运算符&。

                        &a是什么?很明显,&a是指向a的指针,a的类型是int [5],&a的类型就是int (*)[5]。&a的数值是数组a的首地址。

      3:所谓的多维数组。

            3.1 二维数组。

                  首先要明确,C语言中没有真正的多维数组。C语言中的多维数组本质上是一维数组。

                  

3.1.1 定义

                        int b[3][5];

                        看上面的数组b的定义,b是一个一维数组,有3个元素,每个元素都像数组a一样,也就是说,b的每个元素是int [5]。
                        既然所谓的二维数组还是一维数组,那么我们所讲述的一组数组的东西都可以用到所谓的二维数组上。

b是什么?b是int [3][5]类型的变量。只不过这个变量不可被改变。

                  3.1.2 加、减、赋值。

                        b+0是什么?b要做加法了,所以它首先被转换为指向首元素的指针,然后再加0。b的元素的类型是int [5],所以b+0的类型就是int (*)[5]。

                        b-0呢?同上。

                        int (*p1)[5] = b;是什么意思?p1是一个指针,指向int [5]。把b赋值给它时候,b首先转换成指向b的首元素的指针,再赋值。

                        *(b+0)的类型是什么?b+0的类型是int (*)[5],那么*(b+0)的类型就是int [5]。*(b+0)也就是数组b的第一个元素。*(b+1) 也就是数组b的第二个元素。

                        *(b+0)+0的类型是什么?*(b+0)的类型就是int [5],那么*(b+0)+0也就是指向这个整形数组的首元素的指针。也就是说*(b+0)+0的类型是int *型。

                        *(*(b+0)+0)的类型是什么?*(b+0)+0是int *, *(*(b+0)+0)就是int。

                  3.1.3 下标运算符[]

                        E1[E2]不是和*((E1)+(E2))完全等同吗,那么*(*(b+0)+0)也就是*(b[0]+0)也就是b[0][0]。

                  3.1.4取地址运算符&

                        &b是什么?很明显,&b是指向b的指针,b的类型是int [3][5] ,&b的类型就是int (*)[3][5]。&b的数值是数组b的首地址。

            3.2 三维数组

                  int c[2][3][5]。c是个一维数组,有2个元素,每个元素都像b那样,也就是说,每个元素都是个int [3][5]。

                  c+0是指针,类型是int (*)[3][5],指向c的第一个元素。

                  *(c+0)是第一个元素,也就是第一个int [3][5]。

                  *(c+0)+0是什么?*(c+0)是int [3][5],*(c+0)+0就是指向*(c+0)中第一个int[5]的指针。

                  *(*(c+0)+0)是什么?是个int [5]。

                  *(*(c+0)+0)+0是什么?是指向上面的int [5]的第一个元素的指针。它的类型是int *。

                  *(*(*(c+0)+0)+0)是什么?是第一个int。

      4:把数组传给一个函数。

            把数组赋值给一个函数的参数,我们已经知道,赋值的时候数组首先转换成指向首元素的指针。

            数组a可以传给 void f1(int *arr)

            数组b可以传给 void f2(int (*arr)[5])

            数组c可以传给 void f3(int (*arr)[3][5])

            在上面三个函数里,参数arr都是指针了,不再是数组了。所以,数组传给函数的时候,会丢失维度的信息,所以,很多时候,把一个数组传给函数时,还要用另一个参数指明数组是几维的

      PS:

            数组名是指针?错。

            数组名在+,-,赋值运算时被转换为指向数组首元素的指针?对。

            二维数组是二级指针?大错特错。数组就是数组。所谓的二维数组就是一维数组的数组。

            *(a+0)与a[0]完全一样?对。不信就去查C99标准中的[]运算符。

            *(0+a)与0[a]完全一样?对。不信去查标准。但写成这样蛋疼。

            a+0和a有什么区别?区别大了。a是数组,a+0运算时,首先a被转化成指向首元素的指针,然后再做指针加法。也就是说,a+0和a的数值一样,类型不一样。

            int *p=a;赋值运算时,a也被转化为指向首元素的指针?对。

            当数组a做为参数传给函数void foo(int a[])也被转化为指向首元素的指针?对。

            把b传给函数,参数怎么写?void foo(int (*b)[5]),一个指向一组数组的指针。

            &a的类型是什么?是int (*)[5]也就是指向一维数组的指针。但它的值还是a的首地址。

            如果你不太清楚int (*)[3][5]和int *[3][5]的区别,请google “右左原则”或访问此网页,然后在下载下来的东西里找“右左原则”四个字,读过之后,对于声明定义,都看得懂了。

本文来源:http://wildpointer.net/2010/06/10/c_pointer_array/

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值