更改数组中的元素值无法正确反映

时间:2015-06-04 13:13:08

标签: c string initialization

我需要为我的计算机科学项目理解这一点,但我不确定发生了什么,代码是

#include <stdio.h>
void main () {
    char x[6] = "12345\0";
    char y[6] = "67890\0";
    y[7]='A';
    printf("X: %s\n",x);
    printf("Y: %s\n",y);
}

输出是:

  

X:1A345
Y:67890

现在,当我明确指出A时,我不确定为什么x位于y数组的第二个元素中。

6 个答案:

答案 0 :(得分:3)

您的计划正在显示undefined behaviour

记住,

  1. 字符串文字按定义以空值终止。
  2. C数组基于0。索引。
  3. 澄清,

    • 当您尝试将字符串文字(如"12345\0")放入6个char元素的数组中时,编译器将尝试在字符串文字的元素之后添加一个额外的空格,这将成为尝试访问过去分配的内存区域,然后调用undefined behaviour。对于char x[6] = "12345\0";,您不需要\0作为字符串文字的一部分。此外,当您为初始化提供字符串文字时,最好将元素分配(换句话说,数组的大小)留给编译器。你可以使用

      char x[ ] = "12345";
      
    • 然后,拥有维度x的数组,对数组的有效访问权限是从索引[0][x-1]。再次在UB之外访问分配的内存。例如,上面的数组x可以(应该)在类似

      的范围内安全访问
      len = strlen(x);      //get the length of the string
      for (int i = 0; i < len; i++)
      {
           x[i] = i*i;  //access the array
      
      }
      

    尽管如此,请注意main()的推荐签名是int main(void)

答案 1 :(得分:2)

您指定有两个数组,每个数组的大小为六个字节;这意味着它们将具有编号为0到5的元素(因为C使用从零开始的数组偏移,而不是像其他语言中那样基于一个)。

由于您尝试访问y[7],因此您正在访问不属于您阵列的元素。 C不进行边界检查,因此您会进入未定义的行为。在您正在使用的编译器,编译器选项,操作系统,处理器体系结构等的特定组合中,恰好在xy之间没有空格。 ,x落后于y;因此,当您访问数组y末尾后面两个位置的元素时,最终会访问数组x占用的内存。更改其中一个元素(操作系统/编译器(选项)/处理器),结果可能会大不相同。尽管如此,它仍然不会成为你的期望。

另请注意,\0是多余的,并且会导致编译器有效地尝试将"12345\0\0"分配给数组,这是7个字节(因此是溢出)。它可能会发出警告,但不是必须的。

答案 2 :(得分:0)

这里有一个很大的问题:

char y[6] = "67890\0";
y[7]='A';

y是一个包含6元素的数组,其编号为0(即01 ... 5)。这意味着y[7]是无效的表达式,并为其指定值未定义的行为

你在y数组的边界之外写作,由于xy数组放在内存中的方式,你碰巧覆盖了{{1}的第二个元素}}

使用不同的操作系统,编译器或编译器标志可以在内存中生成xx变量的不同位置,代码将在其他位置写入y。甚至可以在'A'内存区域中写入,在这种情况下,由于页面错误异常,操作系统将终止您的程序。

这就是为什么它被称为未定义的行为

答案 3 :(得分:0)

char x[6] = "12345\0";
char y[6] = "67890\0";
y[7]='A';

C / C ++&#39;中的数组索引从零开始。这意味着您只能访问x,y的[0-5]索引。

访问y [7]会导致未定义的行为;在这种情况下,很可能堆栈向下生长并覆盖x的第二个元素(即x [1])。

相关阅读:http://en.wikipedia.org/wiki/Stack_buffer_overflow

答案 4 :(得分:0)

我对此并不是100%肯定,但从我可以看到你已经在数组的边界外写入数据并将其写入相邻块的内存中。

char x[6] = "12345\0";
char y[6] = "67890\0";

混淆可能来自,如果y在x之后声明,那么内存应该如下:

x [0] x [1] x [2] x [3] x [4] x [5] y [0] y [1] y [2] y [3] y [4] y [5 ]

这归结为Big Endian和Little Endian。

在大端存储中,最重要的字节存储在最小的地址中。在小端,它存储在最大的地址。

许多计算机使用的是iittle endian系统(例如,很多英特尔硬件都有),这可能意味着你的数组实际上是这样存储在内存中的:

y [0] y [1] y [2] y [3] y [4] y [5] x [0] x [1] x [2] x [3] x [4] x [5 ]

如果是这种情况,则调用y [7]实际上对应于设置x [1],即x数组的第二个元素。导致数据覆盖并产生以下结果:X:1A345 Y:67890

答案 5 :(得分:-3)

当你在C中分配一个长度为n的数组时,你实际上在长度为n + 1的内存中分配了一个数组,因为编译器为空终止符创建了空间。您不需要添加空终止符。这实际上是导致未定义的行为。

尝试删除空终止符。让我知道会发生什么!