关于数组和指针比较经典的题目
题目1如下
#include<stdio.h> #include<stdlib.h> int main(void) { int a[5]={1,2,3,4,5}; int *ptr=(int *)(&a+1); printf("%d,%d",*(a+1),*(ptr-1)); return 0; }
输出结果为:2,5
在这里主要是考察对指针加减操作的理解
对指针进行加1操作,得到的是下一个元素的地址,而不是在原来指针基础上直接加1,一个类型为T的指针的移动,是以sizeof(T)为单位移动的
首先a的实际类型为int [5],因此对于(int *)(&a+1)而言,先取数组a的首地址,然后进行加1操作,即&a+5*sizeof(int),然后强制转化为整数型指针,此时该指针已经越界,相当于指向a[5],因此ptr实际上等于a+5,所以*(ptr-1)实际上取的是a[4]。
对于*(a+1)来说,就比较简单,先取a的首地址然后指向下一个元素在取值即a[1],这就在于a和&a虽然值相同,但是表达的意义却完全不同,a代表数组首元素的首地址,&a代表数组的首地址。
(int *)(&a+1) int *
a+1 int [5]
&a+1 int [5]*
&a int [5]*
a int[5]
题目2如下:
#include<stdio.h> #include<stdlib.h> int main(void) { 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; }
有了上面一题的基础,很显然可以得出ptr1[-1]的值为4,此处ptr1[-1]等价于*(ptr1-1),
对于第二个输出,首先要弄清楚ptr2的指向,首先(int)a+1表示的值为元素a[0]的第二个字节的地址,然后把这个地址强制转化为(int *)赋给ptr2,在内存布局图中可以看清指向:
在自己电脑中数据以小端模式进行存储,即0x01 0x00 0x00 0x00 0x02 0x00 0x00 0x00 0x03 0x00 0x00 0x00 0x04 0x00 0x00 0x00
因此得到的数据就是0x2000000
题目3
#include "stdio.h" int main() { int a[5][5]; int (*p)[4]; p=(int(*)[4])a; printf("a_ptr=%#p,p_ptr=%#p\n",&a[4][2],&p[4][2]); printf("%p,%d\n",&p[4][2] - &a[4][2],&p[4][2] - &a[4][2]); return 0; }
本题考察的是二维数组的内存问题和数组指针的问题&p[4][2] - &a[4][2]的值为-4。
首先a表示的是数组首元素的首地址,那么a[i][j]元素的首地址为a+i*sizeof(int)*5+j*sizeof(int),以指针的形式表示即为*(*(a+i)+j),则&[4][2]=&a[0][0]+4*5*sizeof(int)+2*sizeof(int)
p是一个指向包含四个元素的数组的指针,则p+1表示指针向后移动了一个“包含四个整型元素的数组”,基本单位为sizeof(int)*4,那么&p[4]=&a[0][0]+4*4*sizeof(int),&p[4][2]=&a[0][0]+4*4*sizeof(int)+2*sizeof(int).
用内存布局能够更清楚的表达出存储关系:
posted on 2014-03-27 21:20 FreedomQQkiko 阅读(858) 评论(0) 编辑 收藏 举报