您的位置:首页 > 编程语言 > C语言/C++

一道c语言指针问题!

2010-10-31 19:35 260 查看
今天闲着无聊,逛了一下别人的blog~发现了这么一道题,我郁闷了,做错了~~晕死~

#include <stdio.h>

int main()

{

int a[5] = {1, 2, 3, 4, 5};

int *pa = (int)(&a) + 1;

printf("%x/n", *pa);

return 0;

}

你觉得答案会是多少涅?

哈哈,没错了,就是2000000!,如果你知道是这个数了,那么请你离开吧,别浪费时间了,你想的是对的!带着你的不屑去看大牛的文章吧

看到这里的人,估计都跟我一样,算错了吧~哈,那就多担待,看看我废话吧!

首先,考查点:一看到这样的题,我想到的是内存的分配图,字节对齐,字节序等问题。

所以我们应该先假定这程序运行的平台,假设该程序运行在intel 32位机上吧,那么我们就可以确定以下几个事:

1 int 是32位的

2 字节序是小端字节序(小端不知道的,自已查去!)

(&a)这个值求的是字符串的地址,即字符串的首地址,但又与a这个字符串的首地址有所差别@

把该地址值强制转化为int型,再把int型的数+1,把该值赋值给pa指针,即此时,该pa指针,指的就是a[0]的第二个字节的地址!

由于pa是整数指针,所以*pa的值就等于,a[0]字节的第二个字符起到a[1]的第1个字节组合而成的整数!

内存分布图如下:

A[0]0xbf9968ac01
0xbf9968ad00
0xbf9968ae00
0xbf9968af00
A[1]0xbf9968b002pa
0xbf9968b100
0xbf9968b200
0xbf9968b300
A[2]0xbf9968b403
0xbf9968b500
0xbf9968b600
0xbf9968b700
A[3]0xbf9968b804
0xbf9968b900
0xbf9968ba00
0xbf9968bb00
A[4]0xbf9968bc05
0xbf9968bd00
0xbf9968be00
0xbf9968bf00
pa指向a[1] 的第一个字节[0xbf9968b0]
然后*pa即是取从该地址开始的四个字节所存储的内容,pa所指向的那个整数值,因为是小端字节序,所以02应在高位,所以该整数变为
02000000!
这就是为什么答案是02000000!明白了吧。

好吧,引申再复习下内存分配与指针的问题吧~

再看下面一个例子:

int x = 1;
int after_array = 2;
int a[5] =
{0x11121314,0x21222324,0x31323435,
0x41424344,0x51525354};
int after_array1 = 1;
char ch_a;
printf("&x = %x/n",&x);
printf("&after_array = %x/n",&after_array);//数组后的一个变量的地址
printf("&after_array1 = %x/n",&after_array1);//数组后的一个变量的地址
printf("&ch_a = %x/n",&ch_a);
printf("a = %x/n",a);//数组第一个元素的值
printf("&a = %x/n",&a);//数组的地址(即第一个元素的地址)
printf("a + 1 = %x/n",a+1);//数组第二个元素的地址
printf("a + 4 = %x/n",a+4);//数组第五个元素的地址
printf("&a + 1 = %x/n",&a + 1);//数组后面的一个变量的地址,
for(x = 0;x < 20;x ++)
{
printf("%2x  ",*(char *)((int)(&a) + x));//打印每一个字节的内容
}
printf("/n");
int *pa = (int)(&a) + 1;
printf("%x/n",*pa);


运行环境:gcc version 4.4.5 (Ubuntu/Linaro 4.4.4-14ubuntu5)

运行结果如下:

&x = bfc89e18
&after_array = bfc89e14
&after_array1 = bfc89e10
&ch_a = bfc89e1f
a = bfc89df8
&a = bfc89df8
a + 1 = bfc89dfc
a + 4 = bfc89e08
&a + 1 = bfc89e0c
14  13  12  11  24  23  22  21  35  34  32  31  44  43  42  41  54  53  52  51
24111213


从上面代码可得出:

1)该程序的所有变量存放在栈里,栈的分布情况是从高地址往低地址分布,

注意:这里有一点需要关注一下,可能是编译器相关的问题,就是数组并不满足先定义先分配的规律,数组分布位置会在所有变量分布完

后的后面分配;当x的地址却要比a数组的地址要高,因为x先定义,

但after_array1的值也比a高!这里我也还没问明白,估计是编译器优化!

2)数组的内存分配是从低到高!即a[0]的地址比a[1]的地址要低。

3)int a[5]={...}

定义该数组之后,a与&a数值相同,但表示的意义完全不一样,可从a+1,&a+1的值可以看出,a+1的步长是4个字节,而&a+1的步长 却是整个数组的长度。

4)内存字节序的问题,*(char *)((int)(&a) + x)从低地址到高地址每个字节的内容,注意:14存放的地址比11的地址要低,如果刚刚第一 个例子看得明白的话,这里应该也知道怎么来的了,包括最后一个输出的值,其实就是跟第一个例子是完全一样的!

这里需要注意的是不能忘了把(&a)强制转化为int型,这里(&a)也可以替换为a,因为这里只需要的是该数组首地址这个“值”在这一点 上这两个是没有区别的!

最后,last but not least!

上面所有的测试都是与平台相关的,如果是64位,或者是16位机那又要另当别论了,所以一开始我就是采用假设是在32位机上的测试!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: