2017-04-12 42 views
-4
#include <stdio.h> 
#include <stdlib.h> 

int main() { 
    int step; 
    double position[4]; 
    position[0] = 1; 
    for (step = 1;step<=4;step++){ 
     position[step] = 99; 
    } 
    return 0; 

} 

可以编译没有错误,并且生成的程序可以运行。C:数组错误初始化的奇怪行为

然而,

#include <stdio.h> 
#include <stdlib.h> 

int main() { 
    int step; 
    double position[3]; 
    position[0] = 1; 
    for (step = 1;step<=3;step++){ 
     position[step] = 99; 
    } 
    return 0; 

} 

也可以编译,但程序不能运行:错误是Abort trap: 6

在上述两种情况下,(错误地)初始化数组的大小为1小于我在填for循环的。但为什么43在这里有所作为?

现在,更有趣的是,

#include <stdio.h> 
#include <stdlib.h> 
#include <time.h> 
#include <math.h> 

int main() { 
    int step; 
    double position[4]; 
    position[0] = 1; 
    position[1] = 99; 
    position[2] = 99; 
    position[3] = 99; 
    position[4] = 99; 
    return 0; 
} 

甚至不能编译(错误是array index 4 is past the end of the array (which contains 4 elements)。那么为什么for循环在这里有所作为?

+4

存在'C'没有数组边界检查。它会有未定义的行为。 –

+4

这是**未定义的行为**。标准不保证*任何*;可能有也可能不会有编译错误或运行时错误。它甚至可能会擦除所有数据,因为没有保证。 – ikh

+0

在前两种情况下,将在运行时对数组赋值。但在第三种情况下,它将在编译时。所以它会抛出错误。 – Rajeshkumar

回答

1

在第三种情况下,编译器提醒您的越界访问。该标准不要求它抱怨,但它是这样做的。

对于前两种情况下,有思维正在发生的事情没有任何意义。你说第一个程序运行罚款。它没有 - 它有一个UB。

为了您的约3 & 4如何改变任何东西,它可能是依赖于堆栈帧是如何奠定了问题。由于对齐差异,返回地址可能在一种情况下被丢弃,但在另一种情况下则不会。您将不得不查看生成的程序集文件以查看实际出错的内容。

https://godbolt.org/g/gqz39q表明,在情况下设置数组大小为3则放置在position%rbp - 32step%rbp - 4。所以如果你写position[3]step被覆盖(我不想考虑写什么)。

当你的position大小为4,它把step%rbp - 4position%rbp - 48。现在你写信给position[4]%rbp - 48 + 4 * 8 = %rbp - 16。这将写入,直到%rbp - 8。所以%rbp - 4step)没有改变。

长话短说,填充救了你的情况下,1但不是在案件2

PS:这又是具体到选择的编译器GCC 6.2 O0优化级别。原因可能在你的情况下完全不同。

+0

是的。奇怪的是'4'没有显示任何符号,但'3'确实给我一些警告。此外,'for'循环显然会做更多的事情,并且在这个意义上“更安全”。 – kyle

1

有在C语言中提到什么,阻止你从编写访问外边界内存的代码,标准只是明确提到,这样做的任何企图将导致undefined behavior

任何诊断,如果提供的是在编译器,也许绑在供给编译选项的自行决定,标准提到的此不作要求。

例如,for some compiler, the last snippet compiles just fine(并接收运行时错误,太)。

注1:在图示的片段,该声明初始化,他们分配

注2:我修改一下代码,但无效的访问取得相同

#include <stdio.h> 

int main(void) { 
    //int step;    // remove unused variable warning 
    double position[4]; 
    position[0] = 1; 
    position[1] = 99; 
    position[2] = 99; 
    position[3] = 99; 
    position[4] = 99; 

    (void) position;   // suppress unused variable warning 

    return 0; 
}