分类: C/C++
2011-11-13 15:26:00
虽然并不存在a[5]这个元素,但是这里也并没有去真正访问a[5],而是仅仅根据数组元素的类型来确定其值。所以这里使用a[5]并不会出错。
~~
对指针进行加1 操作,得到的是下一个元素的地址,而不是原有地址值直接加1。就是在原有地址上加上一个元素的大小。
&a + 1: 取数组a 的首地址,该地址的值加上sizeof(a) 的值,即&a + sizeof(a),也就是下一个数组的首地址,显然当前指针已经越过了数组的界限.(&a可以认为是指向比a高一级的数组的指针,那么&a+1,显然就是&a加上其“元素大小”)
(&a可认为是比a高一级的指针,是指向数组的指针,假如要赋值的话,先定义char ** p;p = &a;或者可认为&a是一个指向指针的指针)
(int *)(&a+1): 则是把上一步计算出来的地址,强制转换为int * 类型,赋值给ptr。
*(a+1): a,&a 的值是一样的,但意思不一样,a 是数组首元素的首地址,也就是a[0]的
首地址,&a 是数组的首地址,a+1 是数组下一元素的首地址,即a[1]的首地址,&a+1 是下一
个数组的首地址。所以输出2
*(ptr-1): 因为ptr 是指向a[5],并且ptr 是int * 类型,所以*(ptr-1) 是指向a[4] ,
输出5。
在Visual C++6.0编译器里,假如用Watch窗口看,a+1是我们想要的结果,但是&a+1并不是的,所以我们就打印出来看,所以我们可以认为这是编译器的一个小BUG。
~~p 的值为0x100000
(unsigned long)p + 0x1 = 0x___?
(unsigned int*)p + 0x1 = 0x___?
(unsigned long)p + 0x1 的值呢?这里涉及到强制转换(转成int,unsigned,long等各种整形数,都是数~!!),将指针变量p 保存的值强制转换
成无符号的长整型数。任何数值一旦被强制转换,其类型就改变了。所以这个表达式其实就
是一个无符号的长整型数加上另一个整数。所以其值为:0x100001。(一个数加上另一个数,不要与整形数组元素加上一个数混了,这里是强制装换!!!)
(unsigned int*)p + 0x1 的值呢?这里的p 被强制转换成一个指向无符号整型的指针。所
以其值为:0x100000+sizof(unsigned int)*0x1,等于0x100004。
看这样一个例子
有了以上的基础在这里我们要注意的就是判断系统的大小端
可以用函数
如果当前系统为大端模式这个函数返回0;如果为小端模式,函数返回1。
也就是说如果此函数的返回值为1 的话,*ptr2 的值为0x2000000。
如果此函数的返回值为0 的话,*ptr2 的值为0x100。
~~函数传递数组的问题
如果数组b 真正传递到函数内部,那i 的值应该为10。但是我们测试后发现i 的值竟然
为4!为什么会这样呢?难道数组b 真的没有传递到函数内部?是的,确实没有传递过去,
这是因为这样一条规则:
C 语言中,当一维数组作为函数参数的时候,编译器总是把它解析成一个指向其首元
素首地址的指针。
~~~能否把指针变量本身传递给一个函数?
这个函数调用,真的把p2 本身传递到了fun 函数内部吗?我们知道p2 是main 函数内的一个局部变量,它只在main 函数内部有效。
(这里需要澄清一个问题:main 函数内的变量不是全局变量,而是局部变量,只不过它的生命周期和全局变量一样长而已。全局变量一定是定义在函数外部的。初学者往往弄错这点。)
既然它是局部变量,fun 函数肯定无法使用p2 的真身。那函数调用怎么办?好办:对实参做一份拷贝并传递给被调用的函数。即对p2 做一份拷贝,假设其拷贝名为_p2。那传递到函数内部的就是_p2 而并非p2 本身。(那么我们怎么传递呢,1.用地址 2.用返回值,上个帖子说过这个问题)
~~~二维数组参数与二维指针参数
前面详细分析了二维数组与二维指针,那它们作为参数时与不作为参数时又有什么区别呢?看例子:
void fun(char a[3][4]);
C 语言中,当一维数组作为函数参数的时候,编译器总是把它解析成一个指向其首元素首地址的指针。这条规则并不是递归的,也就是说只有一维数组才是如此,当数组超过一维时,将第一维改写为指向数组首元素首地址的指针之后,后面的维再也不可改写。比如:a[3][4][5]作为参数时可以被改写为(*p)[4][5]。
传参时的等效
数组参数 等效的指针参数
数组 : char a[10] 指针 : char * p;
数组的数组:char a[3][4] 数组的指针:char (*p)[4]
指针数组: char *a[5] 指针的指针:char **p
~~~
函数指针
A),char * (*fun1)(char * p1,char * p2);
B),char * *fun2(char * p1,char * p2);
C),char * fun3(char * p1,char * p2);
后两个都不难理解,那么第一个是什么呢?
这里fun1 不是什么函数名,而是一个指针变量,它指向一个函数。这个函数有两个指针类型的参数,函数的返回值也是一个指针。
函数指针使用的例子
上面我们定义了一个函数指针,但如何来使用它呢?先看如下例子:
这里需要注意到是,在Visual C++6.0 里,给函数指针赋值时,可以用&fun 或直接用函数名fun。这是因为函数名被编译之后其实就是一个地址,所以这里两种用法没有本质的差别。
~~函数指针数组
现在我们清楚表达式“char * (*pf)(char * p)”定义的是一个函数指针pf。既然pf 是一个指针,那就可以储存在一个数组里。把上式修改一下:char * (*pf[3])(char * p);
~~~函数指针数组的指针
char * (*a[3])(char * p);
char * (*(*pf)[3])(char * p);
pf = &a;
这里的关系就相当于定义一个数组,再定义一个指向数组的指针。当然是这样了
参考《C语言深度解剖》---林正冲