打印无效的C字符串成功

4

我在编写字符串数组的初始化列表时不小心漏掉了一个冒号,然后发现 printf 可以成功打印一个无效的 (0x0) 字符串。以下是我的 C 文件:

#include <stdio.h>
const char *names[3]=
{
    "a",
    "b" // missing colon here made names[1] == "bc"
    "c"
};

int main(int argc, char **argv)
{
    printf("name [2] = %s",names[2]);
    return 0;
}

当我编译并运行它时,出现了name [2] = (null)的结果,这很“奇怪”,因为我认为直接崩溃应该更有意义,不是吗?我难以发现原因,因为我使用的一些字符串不是"b""c",而是像nullnothing等单词。 我的问题是:(1)为什么没有发出警告?(2)为什么printf有这种默认行为?

3
C11标准7.21.6.1规定:"与"%s"相关联的参数必须是字符类型数组的初始元素的指针"。如果您的参数不符合要求,那么将导致未定义行为:可能出现预期和/或意外结果。 - pmg
打印空指针是未定义行为,正如@pmg所指出的那样,一些实现允许将打印空指针作为扩展(例如,如果我没记错的话,MSVC就允许)。 - Aconcagua
“(2) printf为什么有这种默认行为?”-- 实际上并没有。当你将空指针传递给printf时,它是特定实现所选择的方式来避免出错(如果我没记错的话,glibc就是这样做的)。我相信它会检查指针,例如 if (!ptr),如果测试结果为真,则输出 "(null)" - David C. Rankin
你有我的同情 - 这可能是真正的麻烦。我也曾经因为这种事情而受到过伤害。如果编译器能够在某种程度上警告缺少逗号,那确实会很好,但同时,很难看出编译器如何警告缺少逗号,因为这是完全合法的代码。 - Steve Summit
1个回答

6
问题在于你的初始化程序中字符串的拼接!在以下代码中: ``` ```
const char *names[3]=
{
    "a",
    "b" // missing colon here made names[1] == "bc"
    "c"
};

字面值"b""c"将被连接成一个单一的值,"bc",因此,names[]数组的第三个元素将被初始化为零(一个空指针)。

没有警告是因为这种字符串初始化方式在C代码中完全合法。

你的代码实际上是:

const char *names[3]=
{
    "a",
    "bc"
};

这句话的意思是:

这也就是说,这等同于:

const char *names[3]=
{
    "a",
    "bc",
    NULL
};

另外,正如评论中所提到的 (pmgDavid C. Rankin),当x是空指针时,printf("%s", x)" 的行为是未定义的行为。 正如Aconcagua所指出的,许多(或大多数)编译器将像您的一样打印{ null } 或类似的内容; 但某些系统可能会崩溃。


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