数组a和&a的起始地址

pre*_*rem 7 c pointers

在以下两行中,

char a[5]={1,2,3,4,5};
char *ptr=(char *)(&a+1);
printf("%d",*(ptr-1));
Run Code Online (Sandbox Code Playgroud)

这在屏幕上打印5个.当使用a而不是&a时,

char a[5]={1,2,3,4,5};
char *ptr=(char *)(a+1);
printf("%d",*(ptr-1));
Run Code Online (Sandbox Code Playgroud)

这打印1

a和&a都是数组的起始地址.所以为什么这有区别?

char*ptr =&a + 1;

显示警告.

Car*_*rum 12

数组不是指针!有关更多信息,请阅读comp.lang.c FAQ的第6部分.

让我们先来看看你的第二个案例吧,因为它更"正常"而且习惯性.逐行:

  1. 您声明一个a包含5个char元素的数组.
  2. array(a)的名称衰减为指向此上下文中第一个元素的指针.您添加1到该并将结果分配给ptr. ptr指向2.虽然你有一个演员阵容,但是没有必要.
  3. 你减去1ptr,然后间接引用和打印-因此你得到的1.

现在,让我们逐行解决第一个案例:

  1. 您声明一个a包含5个char元素的数组.
  2. 你取地址a,产生一个char (*)[5]类型指针.然后添加1到此指针 - 由于指针算术,这个新指针会5在内存中传递到字节之后.然后你进行类型转换(必需,这次)并将此值赋给ptr.
  3. 你减去1ptr,然后d参考和打印. ptr是a char *,所以这个减法只是将指针从"一个过去的结尾a" 移回一个指向最后一个元素a.因此你得到了5.

最后,原因char *ptr=&a+1;是警告是因为C要求指针类型之间的转换具有显式强制转换.如上所述,&a是类型char (*)[5],而不是 char *,因此要将该值char *赋给变量,您需要显式强制转换.


Rüp*_*ure 10

既然你看起来很陌生,那么让我用简单的语言向你解释,而不是去做严谨的解释.

你看,上面你的程序,a并且&a将具有相同的数值,我相信这就是你的整个混乱lies.You可能想知道,如果他们是相同的,下面应该给下一个地址后,a在这两种情况下,通过去指针算术:

(&a+1) and (a+1)
Run Code Online (Sandbox Code Playgroud)

但事实并非如此!数组的基地址(a此处)和数组的地址不相同! a并且&a可能在数字上相同,但它们不是同一类型.a是类型char*&a为类型的char (*)[5],即,&a是一个指针,指向(地址)和大小5.But的阵列a你也知道的是该阵列的第一个元素的地址 .Numerically它们可用作可从看到相同的插图使用^下面.

但是当你递增这两个指针/地址时,即(a+1)(&a+1),算法是完全不同的.在第一种情况下,它"跳转"到数组中下一个元素的地址,在后一种情况下,它跳过5个元素这就是5个元素数组的大小!.现在明白了?

  1 2 3 4 5  
  ^               // ^ stands at &a

  1 2 3 4 5
           ^     // ^ stands at (&a+1)

  1 2 3 4 5
  ^              //^ stands at a

  1 2 3 4 5
    ^            // ^ stands at (a+1)
Run Code Online (Sandbox Code Playgroud)

以下将给出关于未指定数组绑定的错误,因为未明确指定大小如下所示,当遇到类似(&a + 1)之类的程序时,程序将不知道要"跳转"到多少元素.

char a[]={1,2,3,4,5};
char *ptr=(char *)(&a+1);  //(&a+1) gives error as array size not specified.
Run Code Online (Sandbox Code Playgroud)

现在到你将指针/地​​址递减为的部分(ptr-1).在第一种情况下,在你进入递减部分之前,你应该知道在它上面的语句中发生了什么,它被转换为类型char*:

char *ptr=(char *)(&a+1);
Run Code Online (Sandbox Code Playgroud)

这里发生的是,你"脱光"了原来type(&a+1)这是类型char (*)[5],现在将它转换为类型char*是相同的a,即数组的基址.(再次注意的区别基地址数组和数组的地址在上述语句中的演员和分配之后.所以,其次是在递减printf(),ptr现在阵列,这是最后一个元素之后给出的存储器位置5.

  1 2 3 4 5
          ^     // ^ stands at location of 5, so *ptr gives 5
Run Code Online (Sandbox Code Playgroud)

因此,当您ptr在递减指针后取消引用它,因为*(ptr-1)它打印了5预期的值.

最后,将其与第二个1打印的情况进行对比.看看我使用符号^给出的插图.当你增加aas时a+1,它指向数组的第二个元素,即2你已经将此地址分配给ptr.So,当你减去ptr它时(ptr-1),它会跳回一个元素,现在指向数组的第一个元素,即 1.所以ptr第二种情况下的解除引用给出了1.

  1 2 3 4 5
  ^            // ^ stands at address of 1, so *ptr gives 1
Run Code Online (Sandbox Code Playgroud)

希望这一切都清楚.