a与&a
int a[5]={1,2,3,4,5};
printf("%p,%p,%p\n", a,&a[0],&a);//0x7fff5f989670,0x7fff5f989670,0x7fff5f989670;64位系统
int *p=(int *)a+1;
int *k=(int *)&a[0]+1;
int *q=(int *)(&a+1);
printf("%d,%d,%d\n", *p, *k, *(q-1));//2,2,5
a则是数组首元素的地址
&a[0]是数组第一个元素的地址
&a是整个数组的首地址
a+i = a + i*sizeof(a[0]); 偏移的是一个数组元素。
&a[k]+i = a + (k+i)*sizeof(a[0]); 偏移的是k+i个数组元素。
&a+i = a + i*sizeof(a);偏移的是一个数组长度。
其他
int *n=(int *)((int)a+1);
printf("%p\n", n);//0xfffffffff5b2b791;偏移一个字节
printf("%#x\n", *n);//测试时打印出:Segmentation fault,可能与编译器和Linux系统有关;
如果不报错的话,那么数据元素在小端情况下排列:
0x7fff5f989670:01 00 00 00 02 00 00 00
0x7fff5f989678:03 00 00 00 04 00 00 00
0x7fff5f989680:05 00 00 00
n指针是int类型,对*n取值就取4个字节数据:00 00 00 02,打印出应该是:0x02000000
在大端情况下排列:00 00 00 01 00 00 00 02,那么应该打印出:0x100
扩展
void FunPointArray()
{
char a[5]={'A','B','C','D','\0'};
char (*p1)[5]=&a;//没有问题,p1是指向5个元素的数组指针,而&a代表5个元素数组的地址
char (*p2)[5]=a;//报类型不匹配警告,a代表数组的首地址
printf("p1=%s\n", p1);//p1=ABCD
printf("p2=%s\n", p2);//p2=ABCD
char (*p3)[2]=&a;
char (*p4)[2]=a;
printf("p3=%s\n", *(p3+1));//p3=CD
printf("p4=%s\n", *(p4+1));//p4=CD
char (*p5)[10]=&a;
char (*p6)[10]=a;
printf("p5=%s\n", *(p5+1));//p5=乱码说明已经越界
printf("p6=%s\n", *(p6+1));//p6=乱码说明已经越界
char (*p7)[]=&a;
char (*p8)[]=a;
printf("p7=%s\n", p7);///p7=ABCD,不能用p7+1,报数组边界无固定错误
printf("p8=%s\n", p8);///p8=ABCD,不能用p8+1,报数组边界无固定错误
}
得出:指向数组的指针+1,加的长度为指向的数组长度。
总结:指针变量与一个整数相加减并不是用指针变量里的地址直接加减这个整数,这个整数的单位不是字节而是元素的个数。