超出数组大小的C数组元素设置问题

3

我有这段C代码片段

int numbers[4]={1};

numbers[0]=1; numbers[1]=2; numbers[3]=3; numbers[10]=4;
printf("numbers: %d %d %d %d %d %d\n",numbers[0],numbers[1],numbers[3],numbers[6],numbers[10],  numbers[5]) ;

这段代码的输出结果是:
    numbers: 1 2 3 963180397 4 0

我有几个问题:

  1. 设置numbers [10] 不会出错吗?毕竟数组大小只有4,如果不会出错的话,为什么(因为它没有给出任何错误)。

  2. 为什么打印numbers [6] 会产生垃圾值,而numbers [5] 给出0的值?这也不应该是垃圾值吗。

  3. 设置numbers [10] 有什么影响?我知道它不会增加数组的大小,但它到底是做什么呢?

谢谢!附注:我使用GCC编译代码!!


1
我相当确定所有这些都是未定义的行为。此外,仅因为某些东西是“垃圾”值,并不意味着它必须看起来像垃圾。0也可以是垃圾值。 - Xymostech
对于最后一点,在C中,数组只不过是指向为该数组分配的内存的指针。数组的类型(int、char或其他)由编译器用来知道数组中的值占用多少字节。这允许您使用array[offset]来定位任何值。但由于它也是一个指针,您可以使用*(array + offset)来做同样的事情。_注意:由于加法是可交换的,您也可以使用*(offset + array),这对应于offset[array]。_如果您不知道指针是什么,请阅读此文档:http://cslibrary.stanford.edu/106/ - 7heo.tk
3个回答

2
  1. 这不会导致错误,因为你的数组是在栈上声明的,所以number[10]的作用是在地址number + (10*sizeof int)处写入并覆盖任何可能存在的内容。
  2. 正如Xymostech所说,0可以被视为963180397一样的垃圾。打印numbers[6]将打印存储在地址numbers + (6*sizeof int)处的内容,因此它取决于你的程序如何编译,是否在numbers之前或之后声明了局部变量等。
  3. 参见答案1。

你可以这样做:

int empty[100];
int numbers[4]={1};
int empty2[100];

memset(empty, 0xCC, sizeof empty);
memset(empty2, 0xDD, sizeof empty2);

numbers[0]=1;numbers[1]=2;numbers[3]=3;numbers[10]=4;
printf("numbers: %d %d %d %d %d %d\n",numbers[0],numbers[1],numbers[3],numbers[6],numbers[10],  numbers[5]) ;

现在,当您访问数字数组时,您可以理解您正在覆盖的内容。

这是 - https://dev59.com/ZXRC5IYBdhLWcg3wOeWB#370362,你为什么要将内存块设置为0xCC和0xDD?我的问题是,为什么不在两个中都使用0xDD?为什么第一个要用0xCC? - bad_keypoints
@ronnieaka 不是的,我只是想在numbers数组之前和之后用不同的值初始化内存,以显示每个数组在内存中的起始位置/结束位置。 - koopajah

1
回答你的问题:
  1. 不一定。如果你静态声明了数组,编译器可能会以更大的块来保留内存,或者你可能只是覆盖了栈上数组后面的任何其他内容。
  2. 这取决于编译器,并属于“未定义行为”。
  3. 你将(numbers + 10)设置为等号后面的值。

0

它不会引起任何错误,因为它被衰减为指针算术。

当你写numbers[10]时,它只是numbers + 10 * sizeof(numbers),这是相当正确的。

访问你不应该访问的内存(未分配给你的内存)是未定义的行为,所以你访问的每个越界索引都是垃圾,包括0

访问大于4的索引不会增加数组的大小,正如你所说,而且它也不会做任何事情。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接