我最近开始学习C语言,我正在上一门以C为主题的课程。我目前正在玩循环,我遇到了一些奇怪的行为,我不知道如何解释。

#include <stdio.h>

int main()
{
  int array[10],i;

  for (i = 0; i <=10 ; i++)
  {
    array[i]=0; /*code should never terminate*/
    printf("test \n");

  }
  printf("%d \n", sizeof(array)/sizeof(int));
  return 0;
}

在我运行Ubuntu 14.04的笔记本电脑上,这段代码没有崩溃。它运行到完成。在我学校运行CentOS 6.6的电脑上,它也运行得很好。在Windows 8.1上,循环永远不会终止。

更奇怪的是,当我将for循环的条件编辑为:I <= 11时,代码只在运行Ubuntu的笔记本电脑上终止。它永远不会在CentOS和Windows中终止。

有人能解释一下内存中发生了什么吗?为什么运行相同代码的不同操作系统会产生不同的结果?

编辑:我知道for循环越界了。我是故意这么做的。我只是不明白在不同的操作系统和计算机上,这种行为是如何不同的。


当前回答

它在数组[10]上是未定义的,并给出了之前描述的未定义行为。你可以这样想:

我的购物车里有10样东西。它们是:

0:一盒麦片 1:面包 2:牛奶 3:派 4:鸡蛋 5:蛋糕 6:一杯2升的苏打水 7:沙拉 8:汉堡 9:冰淇淋

购物车[10]未定义,在某些编译器中可能会出现越界异常。但是,很多人显然没有。显而易见的第11件商品实际上并不在购物车中。第11项是指,我称之为“恶作剧项目”。它从未存在过,但它就在那里。

为什么一些编译器给i一个数组[10]或数组[11]甚至数组[-1]的索引是因为你的初始化/声明语句。一些编译器将其解释为:

“为数组[10]分配10个int块和另一个int块。为了方便起见,把它们放在一起。” 和之前一样,但是移动一两个空格,这样数组[10]就不指向i了。 执行与前面相同的操作,但是在数组[-1]处分配i(因为数组的索引不能或不应该为负),或者在完全不同的位置分配i,因为操作系统可以处理它,这样更安全。

一些编译器希望运行得更快,而一些编译器更喜欢安全。这一切都与环境有关。例如,如果我正在为古老的BREW操作系统(基本手机的操作系统)开发一款应用程序,它就不会关心安全性。如果我开发的是iPhone 6,那么它无论如何都能运行得很快,所以我需要强调安全性。(说真的,你读过苹果的应用商店指南吗,或者读过Swift和Swift 2.0的开发吗?)

其他回答

它在数组[10]上是未定义的,并给出了之前描述的未定义行为。你可以这样想:

我的购物车里有10样东西。它们是:

0:一盒麦片 1:面包 2:牛奶 3:派 4:鸡蛋 5:蛋糕 6:一杯2升的苏打水 7:沙拉 8:汉堡 9:冰淇淋

购物车[10]未定义,在某些编译器中可能会出现越界异常。但是,很多人显然没有。显而易见的第11件商品实际上并不在购物车中。第11项是指,我称之为“恶作剧项目”。它从未存在过,但它就在那里。

为什么一些编译器给i一个数组[10]或数组[11]甚至数组[-1]的索引是因为你的初始化/声明语句。一些编译器将其解释为:

“为数组[10]分配10个int块和另一个int块。为了方便起见,把它们放在一起。” 和之前一样,但是移动一两个空格,这样数组[10]就不指向i了。 执行与前面相同的操作,但是在数组[-1]处分配i(因为数组的索引不能或不应该为负),或者在完全不同的位置分配i,因为操作系统可以处理它,这样更安全。

一些编译器希望运行得更快,而一些编译器更喜欢安全。这一切都与环境有关。例如,如果我正在为古老的BREW操作系统(基本手机的操作系统)开发一款应用程序,它就不会关心安全性。如果我开发的是iPhone 6,那么它无论如何都能运行得很快,所以我需要强调安全性。(说真的,你读过苹果的应用商店指南吗,或者读过Swift和Swift 2.0的开发吗?)

这里有两个错误。int i实际上是一个数组元素,数组[10],就像在堆栈上看到的那样。因为你已经允许索引使数组[10]= 0,循环索引i永远不会超过10。令(i=0;我< 10;我+ = 1)。

正如K&R所说,i++是“糟糕的风格”。它增加了i的大小,而不是1。i++是指针数学,I +=1是代数。虽然这取决于编译器,但对于可移植性来说,这不是一个好的约定。

与Java不同,C不做数组边界检查,也就是说,没有ArrayIndexOutOfBoundsException异常,确保数组索引有效的工作留给了程序员。故意这样做会导致未定义的行为,任何事情都可能发生。


对于数组:

int array[10]

索引只在0到9的范围内有效。然而,你正试图:

for (i = 0; i <=10 ; i++)

访问数组[10],将条件更改为I < 10

你声明int array[10]表示数组的索引为0到9(它总共可以容纳10个整数元素)。但是接下来的循环,

for (i = 0; i <=10 ; i++)

将循环0到10意味着11次。因此,当i = 10时,它将溢出缓冲区并导致未定义行为。

所以试试这个:

for (i = 0; i < 10 ; i++)

or,

for (i = 0; i <= 9 ; i++)

我将建议一些我在上面没有发现的东西:

赋值数组[i] = 20;

我想这应该会终止所有的代码..(如果你保持i< =10或ll)

如果运行此程序,您可以确定这里指定的答案已经是正确的[与内存踩脚有关的答案为ex。]