关于数组的混淆"归零"

时间:2018-02-15 19:49:55

标签: c arrays

{{1}}

我的问题是,为什么打印5 0 0 0而不是5 1 2 3?为什么数组"消失了?"

4 个答案:

答案 0 :(得分:6)

在你的情况下

A[0] = 5;

5写为整数,其大小大于char(2,4,8,取决于)。

您的系统似乎是小端,因此在第一个char位置写入5,然后为零。

请注意,如果sizeof(int)为8(在某些系统上可能会发生),则代码不安全并触发未定义的行为,因为它会覆盖mem数组之后的内存(更不用说可能导致操作失败的错位问题,甚至某些处理器上的崩溃

这就是为什么我们必须尊重strict aliasing rule以避免对编译器撒谎,例如,创建一个union,以便编译器可以调整对齐&检查尺寸。

此其他Q& A相关:What happens when you cast a char * address to int * in C when the address is not word-aligned?

答案 1 :(得分:2)

因为在您的系统中sizeof int至少是4的{​​{1}}倍,所以花费sizeof(char)个字节来覆盖您写的所有内容,因为4是一个指向A的指针。(但它可能需要更大)(这种情况通常是这样)如果不是,则表示未定义的行为。

另请注意,我们如何编写它取决于字节顺序。在你的情况下它是小端。因此,基于字节序,它可能也会有所不同。无论这只不过是实验目的。

另外,为了让您了解当int大于sizeof(int)时它是UB的原因 - 那么您将通过4访问此阵列内存中的一些内容并尝试修改它并对其进行更改 - 导致未定义的行为。

答案 2 :(得分:2)

当您尝试使用char *指针对int类型进行别名时,您的代码会显示未定义的行为。这违反了严格的别名规则,因此您的代码就是错误的。

char *类型可以别名其他指针类型,但不是相反。因此,请确保不要违反语言的限制。

答案 3 :(得分:0)

int* A = (int*)(mem); - >风险未定义的行为每个“如果 结果指针未正确对齐引用类型,行为未定义。“C11dr§6.3.2.37

所以代码的其余部分没有实际意义。

使用union来解决对齐和消除锯齿问题。

#include <stdio.h>

int main(void) {
  union {
    int i;
    unsigned char mem[sizeof(int)];
  } u;

  for (unsigned i = 0; i < sizeof(int); i++) {
    u.mem[i] = i;
    printf("%hhu\t", u.mem[i]);
  }
  printf("\n");

  u.i = 5;

  for (unsigned i = 0; i < sizeof(int); i++) {
    printf("%hhu\t", u.mem[i]);
  }
  printf("\n");
  return 0;
}

输出(可能因机器而异)

0   1   2   3   
5   0   0   0

原因:现在未定义的行为 UB已从代码中删除,  Jean-François Fabre好的答案解释了差异。