指针算术;必须先做两次

时间:2015-06-09 19:13:52

标签: c pointers pointer-arithmetic

我在这里有一段代码,我有点困惑。似乎如果我使用:p = &j,只需要两个增量就可以开始遍历a[]

#include <stdio.h>

int main(void) {
  int a[4] = {5,2,6,4};
  int j = a[0];
  int *p;

  p = &j;

  printf("*p = %d\n", *p);
  printf("a[0] = %d\n", a[0]);
  printf("address of a[0] = %p\n", &a[0]);

  printf("\np++\n\n");
  p++;

  printf("*p = %d\n", *p);
  printf("a[1] = %d\n", a[1]);
  printf("address of a[1] = %p\n", &a[1]);

  printf("\np++\n\n");
  p++;

  printf("*p = %d\n", *p);
  printf("a[2] = %d\n", a[2]);
  printf("address of a[2] = %p\n", &a[2]);

  return 0;
}

如果我使用p = &a[0],那么它可以正常工作。为什么当我使用&j时,需要两个p++才能启动。在开始递增数组之前,您可以看到*p = 5两次。为什么是这样?任何帮助将不胜感激。

5 个答案:

答案 0 :(得分:2)

这是一个非常酷的错误,特别是对于刚开始学习C的人来说。理解这种看似奇怪的行为将会提高您对程序运作方式的理解。

您的代码无法正常运行,因为int ja[0]的地址不同,即&j != &a[0]

让我用图解来解释原因。

您的所有本地变量a[], j, p, etc...都会在您的计划call stack上分配。

因此,在您的示例中,堆栈可能假设看起来像这样:

enter image description here

您可以在此精彩艺术图表中看到a的地址为0x1004,而j的地址评估为0x1000。< / p>

仅仅因为2个变量具有相同的值并不意味着它们具有相同的内存地址。这就是这里发生的事情。你给j一个[0]的,但它们仍然是2个单独的,不相关的内存。

为什么递增指针的神秘行为会让您处于a[]的开头可以解释为ja[]都分配在堆栈< / strong>即可。 j的地址可能会在a[]的地址下方。事实上,正如你在我的巨着艺术中所看到的那样,如果我们从&j向上移动4个字节,我们就会到达&a[]

根据Eugene Sh。编辑1:

请注意:递增这样的指针是C程序中未定义的行为。堆栈上的变量排序是未定义的,并且取决于编译器,每次代码重新编译时,您可能会得到不同的结果。请永远不要在真正的计划中做过这件事。执行p ++会导致未定义的行为。

编辑2:

您可以通过打印所有变量的地址来执行很酷的实验。

int main()
{
    int a[4] = {5, 2, 6, 4};
    int j = a[0];
    int* p;

    //in printf, %p stands for "print pointer"
    printf("&a[0] = %p\n", &a[0]);
    printf("&j    = %p\n", &j);
    printf("&p    = %p\n", &p);     //the address of a pointer.... craaazy
    printf("p     = %p\n", p);      //should print same address as &j

    //..............................
}

答案 1 :(得分:1)

您在此处遇到未定义的行为。将j的地址转换为p,您只能获得j的地址,而不是a的开头。第int j = a[0];行将第一个a s元素的分配给j,但不是其地址。通过递增p,您将超出已定义的内存空间的边界,从而调用UB。

答案 2 :(得分:1)

你必须记住如何使指针指向数组的一部分。你正在做的是将值赋给整数的地址(指向所述数组的元素0 ......麻烦)。

以下是一个例子:

#include <stdio.h>

int main(void) 
{

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

  /* Always initialize your variables */
  int *p = NULL;
  int i = 0;

  p = a;

      for (i=0; i < 4; i++)
      {
        printf("Number is = %d,\n", p[i]); // or p + i * sizeof(int)

      }

  return 0;
  }




---Results are----

./a.out 
Number is = 5,
Number is = 2,
Number is = 6,
Number is = 4,

答案 3 :(得分:0)

 int j = a[0]

不使j成为数组a的第一个元素的别名,它定义了一个新的int变量j,它初始化为a的第一个元素的副本。 因此

 p = &j;

p不指向a的任何元素,而是指向单独的变量j。

答案 4 :(得分:0)

由于我无法添加评论,这是我对以前的答案做出反应的唯一方法,我自己也会这样做。

Xofo:实际上,我很抱歉,我困惑了你,就像我困惑自己一样。 它当然可以像我指出的那样p [i],但第二次编辑(在评论中)是错误的。 p [i] = *(p + i),因此您的版本也是正确的。如果要包含sizeof(int),它必须是*(p + [sizeof(int)* i]),我不确定在C中是否可以。