为什么这个arr [0]不等于arr + 0?

时间:2012-12-18 16:39:01

标签: c

您好我很困惑在下面得到解释,有人可以向我解释一下吗?提前谢谢。

#include<stdio.h>
int main(){
    char *arr,c;
    arr = &c;

    arr++;
    *arr = 'a';

    arr++;
    *arr = 'b';

    arr++;
    *arr = 'c';

    arr--;
    arr--;

    printf("\narr 1 = %c",arr);
    printf("\narr 2 = %c",arr[1]);
    printf("\narr 3 = %c",arr[2]);
    getch();
    return 1;
    }

输出是:
arr 1 = a
arr 2 = b
arr 3 = c

但如果更改了行:

printf("\narr 1 = %c",arr);

printf("\narr 1 = %c",arr[0]);

现在输出是:
arr 1 =
arr 2 = b
arr 3 = c

为什么'a'没有打印出来。?

*对于那些质疑程序编码不好的人...我知道使用这样的指针不是一个好的编码实践,但我的问题是为什么arr [0]不打印任何地方作为arr [1] &安培; arr [2]正在打印分配的内容吗?

3 个答案:

答案 0 :(得分:9)

在该计划的第一个版本中,可能发生的是:

  • 编译器将c放在堆栈的某个地址,例如1003(单个字节)。
  • 编译器将arr放在堆栈的某个地址,例如1004-1007(四个字节)。
  • 声明arr = &c;c,1003的地址放入arr
  • 语句arr++;arr添加一个,因此它现在是1004而不是1003。
  • 声明*arr = 'a';'a'写入arr指向的地方。现在这是C标准未定义的行为。当arr设置为&c时,该位置的对象中只有一个字节,并且C标准不保证在对象外部递增该地址后写入其他位置时会发生什么。
  • 在此实例中,1004指向arr,因此您将'a'写入arr的一个字节中。这可怕地改变了arr中的地址。
  • 然后arr++;再次递增地址,*arr = 'b';在某处写'b'。我们不知道在哪里,因为arr的价值很低。
  • 然后arr++;再次递增地址,*arr = 'c';在某处写'c'。我们不知道在哪里。
  • 然后arr--;arr--;将地址返回到'a'写入后的值。
  • 然后第一个printf调用将arr中的值传递给要打印的“%c”说明符。 “%c”用于打印字符,但是传递它的arr是指针。但是,您之前已将'a'写入指针,因此指针的值在其中一个字节中具有'a'
  • 实际上,当“%c”说明符与指针一起使用时,printf的这个实现打印指针值中的一个字节,在这种情况下是您写入{{1}的相同字节}}。所以打印出“a”。 你不能在其他C实现中依赖这种情况。在这种情况下发生这种情况只是因为编译器碰巧将'a'放在内存中arr之后的内存中,所以声明c*arr = 'a';写入'a'。这不会发生在所有C实现中。你得到了“幸运儿”。
  • arr写入'a'后,arr指向某处,但我们不知道在哪里。我们称这个位置为arr
  • 语句xarr++;*arr = 'b';写入'b'位置。
  • 语句x+1arr++;*arr = 'c';写入'c'位置。
  • 然后,两个x+2语句返回arr--;以指向arr。因此xarr[1]处的字符,x+1'b'arr[2]。将这些传递给要用“%c”打印的printf打印“b”和“c”。

在该计划的第二个版本中,当'c'传递给arr[0]时:

  • printf的值是将arr写入其中一个字节而形成的值。这是一些“随机”地址,指向我们没有控制的位置。显然,那里有一个0字符,或者其他一些非打印字符,因此,当'a'传递给arr[0]时,不会打印任何内容。
  • 传递printfarr[1]打印“b”和“c”,因为代码将arr[2]'b'写入了这些位置。

答案 1 :(得分:6)

arr不等同于arr[0],因为arr[0] 取消引用数组。正确的等价物是&arr[0]

顺便说一下,你正在做什么调用未定义的行为,因为在递增arr后,它指向一个无效的内存位置 - 最初它指向一个单个字符,所以你不能假设它之后有什么东西。

答案 2 :(得分:6)

这只是未定义的行为 - arr++; *arr = 'a';是非法的,因为arr指向单个char。任何事情都可能发生。