printf() 在没有双引号的情况下工作,打印随机字符

printf() working without double quotes, prints random characters

我在一次大学测试中偶然发现了这段 C 代码,当我在 Dev-C++ 5.11 编译器上测试它时,它打印了随机字符。我不明白这段代码是如何或为什么起作用的。有人可以启发我吗?

 int main() {
        char a[10] = "%s" ;
        printf( a ) ;
    }

printf 函数签名为:

int printf(const char *format, ...);

它期望格式字符串作为第一个参数和可变数量的参数,这些参数根据格式字符串中的格式说明符进行处理和打印。您问题中的变量 a 正在为其提供格式字符串。随机字符的原因是缺少格式说明符 %s 的参数。以下将正确打印字符串:

printf( a, "Hello World!" );

可以在此处查看格式说明符列表 https://en.wikipedia.org/wiki/Printf_format_string

为什么编译通过?

因为 printf 接受的可变参数在 运行 时处理。并非所有编译器都会在编译时检查格式字符串是否验证参数。即使他们这样做了,他们最多也会发出警告,但仍然会编译程序。

它使用字符串 "%s" 作为格式字符串,并使用未初始化的内存作为 "data"。

它这样做的唯一原因 "something" 是因为编译器显然不够聪明,无法识别格式字符串需要一个参数而提供了零个参数。或者因为编译器警告被忽略 and/or 错误被关闭。

仅供遇到此问题的任何人参考:"Always leave all warnings and errors enabled and fix your code until they're gone"这不能保证正确的行为,但确实会降低 "mysterious" 出现问题的可能性。

这道题有两个部分:遗漏的引号和随机字符。

  1. printf() 只是一个函数。您可以将字符串和其他值作为参数传递给函数。您不必使用文字。您可以同时使用 char *a = "something"; printf(a)(将变量作为参数传递)和 printf("something")(将字符串文字作为参数传递)。
  2. printf()也是一个variadic function。这意味着它可以接受任意数量的参数。您可以使用 printf("hello world")printf("%s", "hello world") 甚至 printf("%s %s", "hello", "world")。一些较旧的编译器不会根据第一个参数(格式字符串)验证您是否确实传递了正确数量的参数。这就是为什么您的代码即使缺少参数也能编译的原因。当程序运行时,代码遍历格式字符串,看到 "%s" 并查找第二个参数以将其打印为字符串。由于没有第二个参数,它基本上读取随机内存并且你得到垃圾字符。