为何GCC允许向长度为0的数组赋值?C语言新手疑问
先看你写的代码:
#include <stdio.h> int main() { printf("enter character\n>>>"); char input[0]; scanf("%5s",input); printf("%s",input); }
下面分几个点解释这个问题:
0长度数组是GCC的非标准扩展
C标准(从C99到最新的C23)都明确禁止显式声明长度为0的数组,但GCC提供了一个自定义扩展,允许编写char input[0];这种代码。这个扩展原本是为结构体的柔性数组场景设计的(比如结构体末尾用0长度数组作为动态数据的占位),但GCC放宽了规则,允许单独定义这类数组。编译器不会检查所有运行时内存问题
编译器的核心职责是验证语法是否符合规则,以及检测部分明显的语义错误,但内存越界这类运行时行为,编译器无法做到100%检测。你用scanf("%5s", input)向0长度数组写入数据,属于典型的缓冲区溢出,但这种问题只有在程序运行时才会触发未定义行为,编译阶段编译器可能无法精准识别你的写入操作会越界——除非你开启更高等级的编译警告。比如你用
gcc -Wall -Wpedantic编译这段代码,GCC会明确警告:warning: ISO C forbids zero-size array 'input' [-Wpedantic] char input[0]; ^~~~~加上
-Warray-bounds还会进一步提示scanf的写入操作越界。C语言的设计哲学:信任程序员
C语言的设计思路是把控制权交给开发者,它不会强制阻止你做危险操作,只会在你违反标准语法时才会报错。0长度数组在GCC扩展里是合法语法,所以编译器允许通过,但使用它来存储数据本质上是在访问不属于你的内存,属于未定义行为——程序可能看似正常输出,也可能直接崩溃、产生乱码,甚至存在安全隐患。正确的写法参考
如果你要接收最多5个字符的输入,别忘了C语言字符串需要末尾的\0结束符,所以数组长度至少要定义为6:#include <stdio.h> int main() { printf("enter character\n>>>"); char input[6]; // 5个输入字符 + 1个'\0'结束符 scanf("%5s", input); // %5s限制最多读取5个字符,避免溢出 printf("%s", input); return 0; }
内容的提问来源于stack exchange,提问作者Josh Reimer

