下面的C代码在VC++6.0下的运行结果是什么?请详细说明原因。
#include <stdio.h>
int main()
{
int a[5]={1,2,3,4,5};
int *ptr1=(int *)(&a+1);
int *ptr2=(int *)((int )a+1);
printf("%x,%x",ptr1[-1],*ptr2);
return 0;
}
学到了新知识
但也受到了极大的打击
将楼上各位牛人的经典解答引用总结一下,已备不时之需:
/*
答案:
ptr1[-1]= 5
*ptr2 = 2000000
*/
/*mask 1*/
int main()
{
int a[5]={1,2,3,4,5};
int *ptr1=(int *)(&a+1);
// a本身就为一个数组的地址,其值=&a[0],即数组第一个元素的地址,对a再取址
// &a = a,似乎没什么不同,其实这里发生了对齐变更,a+1的对齐是以int为界的
// 而&a+1是以整个数组为单位的,即5个int=20字节,这是关键!!!
// 那么&a+1实际是跨越了整个数组,可得ptr1存储了数组a最后一个元素5紧跟着的一个int的地址
int *ptr2=(int *)((int )a+1);
// 同理,(int)a先将其值(地址)转为整型值,再加一成为一个新的整数
// (int *)将这个值转换为一个指向int型变量的指针(地址)
// ptr2即存储了这个地址和指向的变量的类型
printf("%x,%x",ptr1[-1],*ptr2);
// 先解释一下a[-1],即将数组向前偏差一个类型大小的距离
// 数组a的内存布局(16进制):01000000 02000000 03000000 04000000 05000000
// ptr1[-1]
// 你说这里等于什么呢?数组a最后一个元素(5)紧跟着一个int的前面一个元素当然就是5了。
// *ptr2
// ptr2的值为a保存的地址值的绝对值+1,假设a=1000,那么(int)a+1=1001。
// 而后将其再转为(int *)指针,那么指针指向的内存布局为000000 02,即向后移了一个字节
// 那么在little-enddian架构下显示出来为02000000,低位在高地址。
return 0;
}
/*mask 2*/
/*
&a 可以看作是a[5]类型的指针,所以&a+1指向下一个a[5]数组的地址,
也就是说(int*)(&a+1) = (int)a+sizeof(a);
下面是测试代码:
#include "stdio.h"
int main()
{
int a[] = { 1, 2, 3, 4, 5};
printf("a = 0x%x/n", a);
printf("&a = 0x%x/n", &a);
printf("&a[4]+1 = 0x%x/n", &a[4]+1);
printf("(int *)(&a+1) = 0x%x/n", (int *)(&a+1));
printf("(int)a+sizeof(a) = 0x%x/n", (int)a+sizeof(a));
return 0;
}
运行结果如下:
a = 0x12ff6c
&a = 0x12ff6c
&a[4]+1 = 0x12ff80
(int *)(&a+1) = 0x12ff80
(int)a+sizeof(a) = 0x12ff80
Press any key to continue
楼主出这种题就是钻牛角尖。。
*/
/*
mark 3:
楼主这个题确定值得思考一下.
查看一下内存分布情况:
C/C++ code
int a[5]={1,2,3,4,5};
则程序的内存分配(即高地址在前低地址在后)为
01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00
/|/
|
a
第一点:
C/C++ code
int *ptr1=(int *)(&a+1);
首先,&a获得的是数组的地址,这样增长的单元则成了sizeof(a)=20
这样ptr1指向a[5](当然,数组的下标是从0开始,因此正常只有0-4有效.)
ptr1[-1]相当于ptrl-1,也就相当于a[4],因此输出为5.
第二点:
C/C++ code
int *ptr2=(int *)((int )a+1);
(int )a==>能过强制类型转换,此时的(int)a只为一个般的int型值.其值为a[0]的地址.
(int)a+1==>其值为a[0]的地址+1
int *ptr2=(int *)((int )a+1);==>此时指向的地址为00 00 00 02
相当于数值02 00 00 00(十进制为:33554432)
最后由于
printf("%x",*ptr2);==>要求输出为16进制的格式,当然就是2000000
*/
/*
mark 4:
在《C和指针》165页第8章数组的总结中有这样一段话:
在绝大多数表达式中,数组名的值是指向数组第1个元素的指针。
这个规则只有两个例外。sizeof返回整个数组所占用的字节而不是一个指针所占用的字节。
单目操作符&返回一个指向数组的指针,而不是一个指向数组第1个元素的指针的指针。
int *ptr1=(int *)(&a+1); //a是指向数组的指针
int *ptr2=(int *)((int )a+1); //a是指向数组第1个元素的指针
看来基础很重要啊!
ptr1[-1]在《C和指针》里也有解释,等价于*(ptr1-1)。
注意这里ptr是指向int而不是int数组的指针。
*/
/* mark 5:
在c语言里
由于e1[e2]的定义就是 *(e1+e2)
所以(-2)[a]就是*(a-2)
*/
/*
mark 6:
1)记着这样的原则:用最简单的表达,最清晰的设计,完成最复杂的设计,
达到最干练的境界!否则一切都是扯淡!这是工程派的观点
2)该题对于计算机体系结构及C语法的深入探究的确有帮助,但明显的是学术派的.
3)用于对刚毕业的计算机的高求过高,而且有误导的嫌疑!
4)LZ试回忆下你刚出道时真正理解volatile的用法吗?能把复杂的结构体根据
内存对齐的三大原则(规范)计算的准确无误吗?显然不能!
5)计算机及程序设计很容易,不是那么仙道样难学的,更不要以懂一些小技巧就瞒天过海,
欺名盗世还自以为了不起!回想下自己走的路就知道,人真想掌握计算机是多么的容易,
不是那么难的,只要不是傻瓜都可以成为计算机大牛的!!
6)坦率的说,第一次见到本题我也呆了:居然还有这样的高手!
本人5年C,4年底层驱动,天天和代码/计算机底层及硬件打交道,著名大牛的书都认真
拜读过,但是却被这题震住了,但后来一想:用ptr[-1]来寻址的,饶来饶去把自己搞糊涂的
只有LZ这样的顶尖高手!我不的不怀疑Brian .w .Kernighan < <程序设计实践> > 的真实性了!
难道LZ比他老人家还厉害?????
*/
/*
mark 7:
其实我感觉也不是现在的学生差,而是感觉现在的学校的风气不好.
既然楼上各位已经各抒己见了,那小弟也分析一下:
先说
int *ptr1=(int *)(&a+1);
其实(int *)只不过是说明赋个ptr1的是一个int型地址,按c默认的
也是整型,所以去掉(int *)应该不影响结果.那么就只剩下了(&a+1)
a--整型数组的首地址,没有问题.由于这个地址本身为int型,所以a+1
就是从a所指向的地址开始往下移动8个单元(注意:这里所说的单元是
计算机基本单元--字节,整型在C中占两个字节).此时ptr1就是a[4],
但是要记住!读取内存数据的时候是从高字节开始读的(学过汇编语言
的是不会陌生的).所以ptr1[0]不是5,而ptri[-1]才是5.
再说
int *ptr2=(int *)((int)a+1);
(int *)同上.(int)a+1相当于((int)a)+1在这里指针指向的是a的下
一个内存字节单元.那么在读取的时候还是从高地址开始读,在高地址读
出的是02,在低地址读出的是00,所以就出现了结果里的0200;
不知这样解释是否有道理,请各位批评指正!!
*/
Vc6.0的,就是windows下的,那么一般在intel上内存是这样的 小端模式 01 00 00 00 02 00 00 00 …… ^ (int)a + 1,就是向前移了一个字节 01 00 00 00 02 00 00 00 …… ^ 于是结果是02 00 00 00(十六进制) 太简单了,学过汇编这种简直是小儿科!只能说现在的大学生都去吃java,C#的糖衣炮弹了!
楼主的题目本身有点问题;
但是不失为一个好题目;
解答过程如下:
首先,题目要求知道int的长度,我们可以认为默然是32bit系统也就是4;同时我们必须知道是小端还是大端法;
这个直接和答案有关
首先我们来看数组a;他在内存中可能2种方式;也就是和小端和大端有关,我从小地址开始写起
1:00,00,00,01, 00,00,00,02, 00,00,00,03, 00,00,00,04, 00,00,00,05,**
2:01,00,00,00, 02,00,00,00, 03,00,00,00, 04,00,00,00, 05,00,00,00,**
int *ptr1=(int *)(&a+1);
int *ptr2=(int *)((int )a+1);
ptr1 指向了最后的**地址因为&a的类型是int (*)[5];但是这个时候ptr1的类型却是int *的,那么ptr1[-1]就指向了05,或则00
ptr2 指向了第2个00;所以*ptr2 = 00,00,01,00或则00,00,00,02;
http://topic.csdn.net/u/20071127/17/d521c586-bc0a-4c31-bcfe-5d90f0ed7c5e.html