读书人

数组指针的有关问题.请问了.多谢

发布时间: 2012-03-02 14:40:28 作者: rapoo

数组指针的问题.请教了.谢谢
main()
{
int i,a[2]={1,2} ,b[2][2]={1,2,3,4};
printf("%d,%d,%d,%d\n",*a,&a,a,&a[0]);
printf("%d,%d,%d,%d\n",*b,&b,b,&b[0]);


getch();
}
 结果输出     1, -62 ,-62,-62
          -58,-58,-58,-58 
问题一:
    *a 为什么输出的是a[0]的值 而不是数组a的首地址.而*b是输出的却是数组b的首地址?
    既然 a,b代表的都是数组的首地址,假设*是取内容运算符,为啥两个不同啊?  

问题二: 地址为啥是负的,这个问题有可能小白了(当时微机原理没学好). 

延伸问题,上面代码改如下

main()
{
  int i,a[2]={1,2} ,b[2][2]={1,2,3,4},*pa,*pb;
  pa=a;
  pb=b;

  printf("%d,%d,%d,%d\n",*a,&a,a,&a[0]);
  printf("%d,%d,%d\n",*pa,pa,&pa);
  printf("%d,%d,%d,%d\n",*b,&b,b,&b[0]);
  printf("%d,%d,%d\n",*pb,pb,&pb);

getch();

}
 输出结果:
  1,-66,-66,-66
  1,-66,-54,
  -62,-62,-62,-62
  1,-62,-52
  
  既然 pb=b; 那么输出的时候 *pb 应该与 *b一样,结果却不同..
  关于"*" 变量声明的时候是 :指针说明符号.
 而用在表达式时 如上面的printf("%d,%d,%d,%d\n",*a,&a,a,&a[0]); 教材上只是含糊的说了是:取内容运算符. 就没在解释.(真心不希望是教材的失误.那真误人子弟了)
既然是取内容运算符.那a是a[0]的首地址,b是b[0][0]的首地址, *a和 *b 的结果为啥一个是数值,一个是地址啊.不要说*b是取的b[0]的地址,也抛开宏观上的硬说b是个2维数组所以就这种结果.因为输出的时候 printf("%d,%d\n",b,&b[0]);都是-62 既然 b 代表地址,那*b还代表地址..想不通啊.. 我的微机和编译原理啊,看来要饿补了...

请教了.大虾门 ,谢谢了.



[解决办法]
问题二: 地址为啥是负的?
这个问题因为你用的是%d输出,是int类型的数,只要地址的最高位为1就是负数,你如果改为%x输出就会是十六进制的地址值了。
关于问题一比较复杂,尤其是涉及到2维以上的数组,我也没怎么搞明白,能讲一点就是一点吧^_^
a其实是该数组的首地址,你可以将其看作一个指针,对其作*a运算其实就相当于a[0]了,所以*a = 1,但是之所以说数组比较特殊而不能完全看成指针来用是因为你如果查看a的地址,你会发现&a其实就是a[0]的地址,编译器不会给a分配空间来存放他,但是你如果申请一个指针,比如int *c = a,编译器就会给该指针本身申请一个空间来存放,那么&c != a,
简单点说对于一维数组你可以大致把a当作一个指针看。
但是对于2维以上数组,就比较复杂了,它与指针的区别就更加明显了,虽然自己会用算些,但是没有一个原理上的理解,就不给你瞎讲了,留给其他牛人给你说吧。
[解决办法]
问题一:
编译器生成的汇编代码如下

Assembly code
.file    "test.c".section .rdata,"dr"LC0:.ascii "%d,%d,%d,%d\12 \0"。。。。。。。。。。。。leal    -32(%ebp), %eax //得到数组a的首地址也就相当于asubl    $72, %esp       //分配数组和参数的空间movl    %eax, 16(%esp)  //printf的第五个参数&a[0]movl    %eax, 12(%esp)  //printf的第四个参数amovl    %eax, 8(%esp)   //printf的第三个参数&amovl    $1, %eax        //*a的结果存入movl    $1, -32(%ebp)   //a[0] = 1movl    $2, -28(%ebp)   //a[1] = 2movl    $1, -24(%ebp)   //b[0] = 1movl    $2, -20(%ebp)   //b[1] = 2movl    $3, -16(%ebp)   //b[2] = 3movl    $4, -12(%ebp)   //b[3] = 4movl    %eax, 4(%esp)  //printf的第二个参数*amovl    $LC0, (%esp)   //printf的第一个参数 串"%d,%d,%d,%d\12 \0"call    _printf        //调用printfmovl    $LC0, (%esp)   //printf的第一个参数 串"%d,%d,%d,%d\12 \0"leal    -24(%ebp), %eax //&b[0] 存入movl    %eax, 16(%esp)  //printf的第五个参数&b[0]movl    %eax, 12(%esp)  //printf的第四个参数bmovl    %eax, 8(%esp)  //printf的第三个参数&bmovl    %eax, 4(%esp)  //printf的第二个参数*bcall    _printf        //调用printf
[解决办法]
main()
{
int i,a[2]={1,2} ,b[2][2]={1,2,3,4};
printf( "%d,%d,%d,%d\n ",*a,&a,a,&a[0]);
printf( "%d,%d,%d,%d\n ",*b,&b,b,&b[0]);


getch();
}
 结果输出     1, -62 ,-62,-62
          -58,-58,-58,-58 
问题一:
    *a 为什么输出的是a[0]的值 而不是数组a的首地址.而*b是输出的却是数组b的首地址?
    既然 a,b代表的都是数组的首地址,假设*是取内容运算符,为啥两个不同啊? 

a的类型是 int [2],忽略掉其中的2,类型为int [], 和int*等价, 结果明显
b的类型是 int [2][2], 忽略掉第一维的信息 int [][2], 和int (*)[2]等价,也就是把b看作一个指向二维数组的指针,*b的值就是这个数组的首地址了
问题二: 地址为啥是负的,这个问题有可能小白了(当时微机原理没学好).
有人回答了
////////////////////////////////////////////////////////////////////////////


main()
{
  int i,a[2]={1,2} ,b[2][2]={1,2,3,4},*pa,*pb;
  pa=a;
  pb=b;

  printf( "%d,%d,%d,%d\n ",*a,&a,a,&a[0]);
  printf( "%d,%d,%d\n ",*pa,pa,&pa);
  printf( "%d,%d,%d,%d\n ",*b,&b,b,&b[0]);
  printf( "%d,%d,%d\n ",*pb,pb,&pb);

getch();

}
 输出结果:
  1,-66,-66,-66
  1,-66,-54,
  -62,-62,-62,-62
  1,-62,-52
  
  既然 pb=b; 那么输出的时候 *pb 应该与 *b一样,结果却不同..
  关于"*" 变量声明的时候是 :指针说明符号.
 而用在表达式时 如上面的printf( "%d,%d,%d,%d\n ",*a,&a,a,&a[0]); 教材上只是含糊的说了是:取内容运算符. 就没在解释.(真心不希望是教材的失误.那真误人子弟了)
既然是取内容运算符.那a是a[0]的首地址,b是b[0][0]的首地址, *a和 *b 的结果为啥一个是数值,一个是地址啊.不要说*b是取的b[0]的地址,也抛开宏观上的硬说b是个2维数组所以就这种结果.因为输出的时候 printf( "%d,%d\n ",b,&b[0]);都是-62 既然 b 代表地址,那*b还代表地址..想不通啊.. 我的微机和编译原理啊,看来要饿补了...
//////////////////////////////////////////////////////////////
int i,a[2]={1,2} ,b[2][2]={1,2,3,4},*pa,(*pb)[2];
这样的就对了

你用一个int [2][2](或者 int [][2] int (*)[2])给int*赋值的时候有类型转换!
也就是把b的首地址重新解释为int*,当然*pb和*b不一样了...

读书人网 >C语言

热点推荐