<!-- @page { margin: 2cm } P { margin-bottom: 0.21cm } PRE.western { font-family: "DejaVu Sans Mono", monospace } PRE.cjk { font-family: "DejaVu Sans", monospace } PRE.ctl { font-family: "DejaVu Sans Mono", monospace } A:link { so-language: zxx } -->
刚才在 CSDN -CSDN 社区 -C/C++ -C 语言 里面发现了网友们在讨论一个 printf 函数 输出结果的问题。因为自己最近在看一个和 scanf 函数 相关的问题,也就进去看了看(原帖链接:http://topic.csdn.net/u/20100801/07/9775eb1c-d6da- 4cb1-a968-c16bc72cc958.html?77377 )。
-------------------------------------------------------------
下面就网友们的观点进行描述:
楼主: winematrix
写出(以下程序中)printf 的输出结果。假设这些代码运行在intel cpu, 32bit. integer 四个bytes.
//code starts :
#include <stdio.h> int main() { int a[ 5 ]={ 10 , 20 , 30 , 40 , 50 }; int b[ 5 ]={ 100 , 200 , 300 , 400 , 500 }; int *ptr = ( int *)(&a+ 1 ); int *t = ( int *)(&a - 1 ); printf( "%d %d %d /n" , *(a+ 1 ), *(ptr- 1 ), *(t+ 1 )); }
//code ends.
1#: bluejays :
*(a+1) 输出 a[1] ,也就是20
*(ptr-1) 输出a[4] ,也就是50 。
ptr 指向a[5] 的位置,所以ptr-1 就是a[4]
*(t+1) 这个就不一定了。t 指向a[-5] ,*(t+1) 就是a[-4] ,这个位置是什么值,我觉得依赖于编译器。
2# bluejays :
我的编译器a 的地址是0x22ccc0 ,b 的地址是0x22cca0 ,也就是说编译器给b 分配了8 个int 的空间,b[0] 在a[-8] 的位置上,所以a[-4]
的位置是b[4] ,*(t+1) 输出500,
ptr 和t 分别是0x22ccd4 、0x22ccac
5# wibnmo :
b 地址为:12ff58
a 地址为:12ff6c
&a+1 的地址为:12ff80 (这里的1 是指a 整个数组)
10 :12ff6c
20 :12ff70
30 :12ff74
40 :12ff78
50 :12ff7c
同样&a-1 为:12ff58 这正是b 数组的起始地址。
int *ptr = (int *)(&a+1);
ptr 为指向12ff80 的指针,ptr-1 为12ff7c, 即元素50.
int *t = (int *)(&a -1);
t 为指向12ff58 这块区域的指针, 这里正是数组b 的区域,t+1 即是元素200 的地址。
【以上内容在编辑格式上与原帖略有不同,望原作者见谅。】
--------------------------------------------------
以下网友们的问答,我学习总结如下:
[1]:
关于编译后 两个数组 的地址
(b 地址为:12ff58----a 地址为:12ff6c ,这里引用 wibnmo 网友的分析,没有自己的分析着实不该,这里暂且用以说明问题。)
解释如下:
由于 a[5] b[5]
同为局部变量,编译器在进行内存分配时,把他们放在了数据栈之上。 而栈的生长方式为向下增长,即在源代码中
出现较晚的变量将会在较低地址上获得自己的存储区域。
[2]:
有关地址运算 int *ptr = (int *)(&a+1 ); int *t = (int *)(&a -1 ); 的问题:
根据网友们的分析,我得出以下结论,
int *ptr=(int *)(&a+1)
所做的是 在以a[] 为“格式单元”(0x12ff6c--0x12ff7c )的内存地址之上,加上一个 int * 类型长度的内存空间(这里是4
个字节长度),所得的地址(0x12ff80) 放入ptr 中。
int *t = (int *)(&a -1 );
所做的工作同以上分析类似,在此不再说明。
[ 补—1]
:以上分析不妥,再行分析。
int *ptr=(int *)(&a+1) ;这里 (&a + 1) 经过测试,等价于(0x12FF7F + 1) 。
而我的测试: int *t1 = &a ,则有0x12FF6C 。这是可以理解的。至于上面一行的情况,目前我的解释和原来的讨论大体一致,采用
“格式单元”的说法(有待学习纠正)。不同之处在于所加的内存空间长度为1 个字节长度,而不是 int * 类型的长度。
[3]: int *t = ( int *)(&a + 1 ); 与 int t= &a + 1; 的区别。
经过测试,在实现的结果上没有区别。至于更多的讨论,这里先不去考虑。
[4]: 贴出我的一些测试及其结果:
#include <stdio.h>
int main()
{
int a[5] = {1,2,3,4,5};
int b[5] = {6,7,8,9,a};
int *t1 = &a + 1;
int *t2 = (int *)(&a + 1);
//printf("a==%X;/nb==%X;/nt1==%X;/nt2==%X;/n",&a,&b,&t1,&t2);
//printf("a[0]==%X;/nb[0]==%X;/nt1==%X;/nt2==%X;/n",&a[0],&b[0],&t1,&t2);
//printf("int * ==%d;/na[5]==%X;/nb[5]==%X;/nt1==%X;/nt2==%X;/n",sizeof(int *),&a[4],&b[4],&t1,&t2);
printf("int * ==%d;/na[5]==%X;/nb[5]==%X;/nt1==%X;/nt2==%X;/n",sizeof(int *),&a[4],&b[4],t1,t2);
return 0;
}
// [Conclusions]:
/*------------
<1>
printf("a==%X;/nb==%X;/nt1==%X;/nt2==%X;/n",&a,&b,&t1,&t2);
a==13FF6C;
b==13FF58;
t1==13FF54;
t2==13FF50;
Press any key to continue
<2>
printf("a[0]==%X;/nb[0]==%X;/nt1==%X;/nt2==%X;/n",&a[0],&b[0],&t1,&t2);
a[0]==13FF6C;
b[0]==13FF58;
t1==13FF54;
t2==13FF50;
Press any key to continue
<3>
printf("a[5]==%X;/nb[5]==%X;/nt1==%X;/nt2==%X;/n",&a[4],&b[4],&t1,&t2);
a[5]==13FF7C;
b[5]==13FF68;
t1==13FF54;
t2==13FF50;
Press any key to continue
<4>
printf("int * ==%d;/na[5]==%X;/nb[5]==%X;/nt1==%X;/nt2==%X;/n",sizeof(int *),&a[4],&b[4],&t1,&t2);
int * ==4;
a[5]==13FF7C;
b[5]==13FF68;
t1==13FF54;
t2==13FF50;
Press any key to continue
<5>
printf("int * ==%d;/na[5]==%X;/nb[5]==%X;/nt1==%X;/nt2==%X;/n",sizeof(int *),&a[4],&b[4],t1,t2);
int * ==4;
a[5]==13FF7C;
b[5]==13FF68;
t1==13FF80;
t2==13FF80;
Press any key to continue
-------------*/
[5]:
关键的问题没有解决,看来得在 指针方面 再做加强了。