2017-08-25 186 views
2

为什么没有在意外打印2D数组的一个维度时出现编译时错误?此代码为什么打印地址?

#include <stdio.h> 

void main() { 
    int i; 
    int arr[2][3] = { 1, 2, 3, 4, 5, 6 }; //<- Declared a 2D array 

    for (i = 0; i < 6; i++) { 
     printf("%d\n", arr[i]); // <- Accidently forgot a dimension 
    } 
} 

我应该收到编译时错误,但我得到了一组地址!为什么?在编译器的情况下,arr[0]是什么意思?

+2

因为* array *类型(这是'arr [i]'的类型)*衰减*到指针。 –

+0

它应该会产生警告(类型为int *'的错误格式说明符'%d'),如果启用的话。 http://coliru.stacked-crooked.com/a/8d995ce5a6a38cb2 – tkausl

+1

从技术上讲,输出是未定义的行为,因为'%d'不能用于指针。 –

回答

8

阵列型计算结果为指针在大多数情况下,第一阵列元件的表达式(一个显着的例外,除其他外,是sizeof操作符)。

在你的例子中,arr[i]数组类型。所以它的计算结果为int (*)[](指向数组的指针)类型的指针。这就是打印的内容。用%d打印指针是未定义的行为,因为printf()将读取指针,就好像它是int一样。

1

菲利克斯帕尔曼的答案解释了观察到的行为。

关于你的第二个问题:你没有得到警告的原因是你没有要求他们。

编译器在默认情况下非常宽松,并且会接受包含明显未定义行为的破坏代码。这个特定的不明显,因为printf()在初始格式字符串之后接受任何数量的额外参数。

您可以指示您的编译器发出许多有用的警告,以避免愚蠢的错误并检测到非显而易见的编程错误。

  • gcc -Wall -Wextra -Werror
  • clang -Weverything -Werror
  • 选项/W3/W4与Microsoft Visual Studio。

gccclang会抱怨数组arr马虎初始化。它应该是:

int arr[2][3] = { { 1, 2, 3 }, { 4, 5, 6 } }; 

打印循环的确令人惊讶,你真的打算用单循环打印数组吗?

还要注意,没有参数的main的标准原型是int main(void)