我来到这个question并看到这一行
printf(&c[i]);
我想知道,这是一个有效的语法吗?打印不带格式说明符%s
的字符串/字符串文字不会导致未定义的行为或约束违规?
如果这是一个有效的语法,那么它的用途是什么?
我编译了这段代码
#include <stdio.h>
int main()
{
char *c = "Hello World";
printf(c);
printf("\n\n");
printf(&c[0]);
return 0;
}
并且在没有输出任何警告/错误的情况下进行编译
Hello World
Hello World
答案 0 :(得分:3)
这是不明智的(特别是如果所说的字符串来自用户),但这不是非法的。
有关条款将是第7.19.6.1节第3段(强调我的):
格式应为多字节字符序列,以其初始移位状态开始和结束。格式由零或多个指令组成:普通的多字节字符(不是%),它们不加改变地复制到输出流中;和转换规范,每个都导致获取零个或多个后续参数,根据相应的转换说明符转换它们(如果适用),然后将结果写入输出流。
您应该使用fputs(c);
或fprintf("%s", c);
来确保您的字符串不会被意外解释为包含指令。
答案 1 :(得分:1)
它有效,但不推荐。假设你有
char *c = "We have a 30%sale!";
然后,您的printf
语句将访问垃圾内存,尝试解析%s
。
答案 2 :(得分:1)
使用printf
是不安全代码的主要示例:无法从源代码(特别是类型系统);正确性取决于值而不是类型。这种代码可能的事实使C成为“不安全的语言”。例如:
void f(char const * p)
{
printf("%s", p); // this is safe!
printf(p); // correct if the string contains no format specifiers;
// undefined behaviour otherwise
}
重复:程序的正确性取决于其运行时特性,并且无法保证静态。
你永远不应该写这样的代码!
答案 3 :(得分:0)
这是允许的,但它有风险。考虑下面的一些功能。
void foo(const char* s) {
printf(s);
}
如果输入参数中有%s
之类的内容,它可能会生成核心。
答案 4 :(得分:0)
它有效,因为c
是一个指向字符串开头的指针(换句话说,它是指向字符串第一个符号的指针)。 c[0]
会为您提供一个字符W
。 &
让你指向这个char
。您在代码中使用的构造只是通过指针获取值并立即返回此值的指针。例如,c[i]
等于*(c+i)
。
为什么会这样?因为printf()
函数接收一个指向string的指针作为参数。它会打印从指针开始到'\0'
符号的所有符号。
请详细了解C语言中的指针以及如何实现C数组和C字符串。