数组名 和 指针

这一段代码的运行结果如下:

从运行结果我们知道,&a和a的值是一样的,但是a + 1 和 &a +1的结果就完全不一样,这是为什么呢?哎,为什么总是这么多,今天早上看到百度新闻上面竟然报道有些地方在抢购矿泉水,为什么呢?又和抢盐运动一样?

哦哦,我们知道a是数组名,代表数组的首地址,a+1,就是数组的下一个元素的地址。

a = 0xbfea014c a + 1 = 0xbfea0150 相差多少?呵呵,你懂的,a+1正好是下一个元素的地址吧。

我们再来看看&a 和 &a + 1吧:

&a = 0xbfea014c &a + 1 = 0xbfea0160,相差多少?聪明的你一定知道,是20。这时我们知道,&a + 1已经到数组的最后一个元素的下一个地址。

到这里我们来总结一下,然后在看凌云若叶的面试题:

int a[5],a是数组名,它其实就是一个符号,代表数组的首地址和&a[0]一个意思。

&a的值也是数组的首地址,但是意义完全不一样。我们可以这样理解&a呢,是取整个数组的地址,那&a+1呢就是一次移动一个数组。

好,再来看凌云若叶的面试题

运行结果:

想一想为什么?

通过我刚刚的一番忽悠,我想你应该差不多了。如果你做错了,也许你还差点什么东西,不用着急,我们接着看:

#include <stdio.h>
        int main()
        {
                int a[5]={1,2,3,4,5};//数组的定义并赋值,不知道这个,建议回家
                int *ptr1=(int *)(&a+1);//这时这个,ptr1保存的是最后一个元素 的下一个地址
                int *ptr2=(int *)((int )a+1);//(int)a,是不是把数组的地址强转成整 型,这样+1,只是在个这个地址值加了一个1。还记得a+1吗,由于a是数组的名首地址,a+1的值是多少?你懂的。
                printf("%x,%x",ptr1[-1],*ptr2);//ptr1[-1],下表是-1?哇塞,不可能吧?笨笨都是这样想,但我们是开发人员,我们知道ptr1[-1],其实可以看成*(ptr1 - 1)。还记得ptr1保存的值吗?知道ptr1[-1]的值吧.

  return 0;
        }





------------------------------------------------------------------------------------------------华丽的分割线-------------------------------------------------------------------------------------------------------------------




数组和指针


数据软件开发二部 王治春


20070412


 


数组和指针之区别列表


以下面代码为例:


char*p;


chararray[100];


说明如下:


1       因为任何类型的指针变量(针对我们用的32CPU而言)的长度为4,故sizeof(p)4;但sizeof(array)100.这一点是由编译器在编译阶段确定的,即编译器对于sizeof(p)是直接以常数4替换的,对sizeof(array)是直接以100替换的。由此也可知道,用sizeof不但可读性、可扩展性好,而且丝毫不降低代码效率(包括时间和空间上的)。


2       sizeof(*p)sizeof(array[0])则相同,都为1


3       n为一整数,p[n]等价于*(p + n)array[n]等价于*(array+ n),即不管是指针还是数组,都有这两个等效的表示方法


4       数组形式的形参本质上是指针。后面详述。


5       array在许多情况下代表第一个元素的地址,即&array[0]。例如


p = array; /* 等价于 p = &array[0]; */


fun(array); /* 等价于 p = fun(&array[0]); */


这个现象让许多人得出“数组即指针”的错误结论。


6       但数组毕竟是数组,当arraysizeof或地址时,array代表整个数组,这时它不能替换为 &array[0]。例如:


sizeof(array)100,而sizeof(&array[0])等于sizeof(char*);


&array表示整个数组的地址,它可以赋值给一个指向同类型数组(即100char变量组成的数组)的指针。而 &(&array[0])表示什么?什么也不是,根本不合语法(编译不过)。



使用数组名时,前面加不加&符号有何区别?


void main()


{


 char a[4];


 void *b;


 void *c;


 


 b=a;


 c=&a;


}


上面的代码中,b=a; c=&a;二者都获得的是数组a的首地址,所以bc的值相同。


 


但从本质上说,a&a的类型是不同的:在b=a中,a等价于&a[0],所以此处是当作char*(即指向char变量的指针)类型使用的;而&a表示数组a的地址,所以其类型是“指向含4char元素的数组的指针”。


 


看下面的例子(VC下编译的结果),就说明问题


voidmain()


{


     char a[20];


     char *b,(*c)[20]; /* c的类型为“指向含20char元素的数组的指针” */


     b=&a; /* 编译不过,因类型不匹配 */


     b=a; /* OK */


     c=&a; /* OK */


     c=a; /* 编译不过,因类型不匹配 */


}


由于c指向的是含20char元素的数组,故c+1其实是对c的值加了20,可作如下测试:


printf(%u\n, (unsignedint)(c + 1) - (unsigned int)c);



观察打印为20.


 


但下面的代码编译则无任何问题,因为b cvoid*,可接收任何类型的指针的赋值


voidmain()


{


     char a[20];


     void *b, *c;


     b=&a;


     b=a;


     c=&a;


     c=a;


}



指向数组的指针的应用


指向数组的指针应用不多,但偶尔也会碰到,下举一例(部门人员碰到的):


char a[10][20], b[10][20];



if (..)


{


   a[i][j]


}


else 


{


   b[i][j]   /* 此分支与上一分支的唯一区别是:前者是对a,后者是对b操作 */


}


两分支代码除a b之分外,完全相同。这种代码浪费空间,且不易维护——两处要同步更改。


借用数组指针,可以这样:


char(*p)[10][20];/*括号不能省略,否则p变成了指针构成的数组*/


if (..)


{


   p = &a;


}


else


{


   p = &b;


}


(*p)[i][j]  /* 仅一份代码 */


或者这样:


char(*p)[20];/*括号不能省略,否则p变成了指针构成的数组*/


if (..)


{


   p = a;/* a看成&a[0],就知道其类型与p是匹配的 */



}


else


{


  p = b;


}


p[i][j]  /* 仅一份代码 */




数组形式的形参本质上是指针


 


void Fun1(char v[100])


{


    int n =sizeof(v);


   


    v++;


}


完全应该这样理解:


void Fun1(char *v)


{


    int n =sizeof(v);


   


    v++;


}


1 Fun1v++是合法的。


2 sizeof(v)的值不是100,而是等于sizeof(char*),即4


 


void Fun1(char v[100])void Fun1(char *v)以及void Fun1(char v[])是完全等价的写法。我们应按void Fun1(char *v)来理解,编译器也都是按这种方式体现的意义来编译的。写代码时,从语法上说可以随便用哪种形式。但是从习惯上来说,如果设计该函数时是打算接受上层函数(即调用者)的数组名作为实参,则通常定义为数组形式(char数组除外);如果设计该函数时是打算接受上层函数(即调用者)的某一个变量的地址作为实参,则通常定义为指针形式。






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值