4.4 指针数组和数组指针
4.4.1 指针数组和数组指针的内存布局
指针数组:首先它是一个数组,数组的元素都是指针,数组占多少字节由数组本身决定。它是“存储指针的数组”的简称。
数组指针:首先它是一个指针,它指向一个数组。在32位系统下永远是占4个字节,至于它指向的数组占多少字节并不知道。它是“指向数组的指针”的简称;
下面来考考到底哪个是数组指针 、哪个是指针数组?
(A)int *p1[10];
(B)int (*p2)[10];
分析:首先我们要明白优先级的问题:
(A)“[ ] ”的优先级比“ * ”要高,p1先与“[ ]”结合,构成了一个数组的定义,数组名为p1,int *修饰的是数组的内容,即数组的每个元素。这个数组,其包含了10个指向int类型的数据指针,即指针数组;
(B)“()”的优先级高于“[ ]”,“*”与p2构成了一个指针的定义,指针的变量名为p2, int 修饰的是数组的内容,即数组的每天元素。数组这里并没有名字,是个匿名数组。现在我们清楚p2是一个指针,它指向一个包含10个int 类型的数据数组,即数组指针。
char (*)[10] p3; //也是数组指针。char (*)[10]是指针类型,p3是指针变量名。
4.4.3 再论a 和 &a之间的区别
回顾一下知识点:
a 和 &a的值是相同的,但是意义不相同;a是数组首元素的首地址; &a是整个数组首地址;
下面来看一下:
- int main()
- {
- char a[5]={'A','B','C','D' }
- char (*p3)[3] = &a;
- char (*p4)[3] = a;
- return 0;
- }
上面对p3和p4的使用,哪个是正确的?p3+1 的值会是多少?p4+1 的值?
解析:
在C语言中,赋值符号“=”两边必须是相同的类型,p3定义的“=”两边都是数组的指针,一致! p4定义的“=”两边数据类型不一致!左边的类型是指向整个数组的指针,右边的数据类型是指向单个字符指针。由于&a和a的值一样,而变量作为右值时编译器只是取变量的值,所以运行并没有什么问题。(不过警告你别这么用)
(*p3)[3] = &a; 而 p3+1 后,p3指向元素'D' char (*p4)[3] = a; p4+1后,p4同样指向'D'
4.4.4 地址的强制转换
先看下面的例子:
struct Test
{
int Num;
char *pcName;
short sDate;
char cha[2];
short sBa[4];
}*p;
假设p的值为0x100000 ,那么下面这些表达式的值分别是多少?
1).p+ 0x1 =0x_____?
2).(unsigned long)p +0x1 =0x____?
3).(unsigned int*)p +0x1 =0x____?
解析:
1).指针变量与一个整数相加减并不是用指针变量里的地址直接加减这个整数,这个整数的单位不是字节而是元素个数 p+0x1 的值为0x100000 + sizeof(Test)*0x1 至于此结构体的大小为20字节,最后计算出p +0x1 的值为0x100014(十进制1048576+20);
2).(unsigned long ) p+ 0x1 的值呢?这里涉及强制转换,将指针变量p保存的值强制转换成无符号长整型数。任何数值一旦被强制转换,其类型就改变了,所以这个表达式其实就是一个无符号的长整型数加上另一个整数,其值为0x100001。
3).(unsigned int *)p +0x1 的值呢? 这里的p被强制转换成一个指向无符号整型的指针,所以其值为:0x100000 +sizeof (unsigned int) *0x1 =0x100004
上面似乎没有什么技术含量,下面来个有技术含量的:在x86系统下,其值为多少?
int main()
{
int a[4] ={1,2,3,4};
int *ptr1=(int * )(&a +1);
int *ptr2 =(int*)((int)a+1);
printf("%x ,%x",ptr1[-1],*ptr2);
return 0;
}
这个据说在网上难倒了n多人,但据说懂汇编的人就会解....
在懂&a+1 和a+1区别的基础上
下面来分析一下:由前面小节的知识知道,p1指向的是一个越界地址,即a[3]的末尾,a[4]的首地址。所以p1[-1]被解析成*(p1-1),所以打印出4。
我们知道,a是数组首元素的首地址,在第4行被转换成了一个整数,然后加1。我们又知道数组中都是int型,每个元素有4个byte。于是p2指向的是元素a[0]中四个byte中的第2个(第1个是a)。所以,p2指向的内存块包括a[0]的后3个byte和a[1]的第一个byte。具体打印的值,还依据系统的采用的是大端还是小端的存储模式。