有人能解释一下这些输出背后的逻辑吗?我猜这里*
被用作抑制字符,但我无法弄清楚输出。
main()
{
char *s="hello world";
int i=7;
printf("%.*%s",s);
}
输出:%s
如果将printf语句替换为printf("%,*%s",s)
,那么你的输出将是,* hello world ???
答案 0 :(得分:6)
printf格式字符串"%.*%s"
无效。 *
字符不被视为转换抑制说明符,而是作为指定精度的.
字符的参数。
比较类似:
printf("%.*s", 3, str);
其中*
将下一个参数(3)作为精度字段(对字符串具有特定含义),然后s
获取字符串。由于3
是常量,因此相当于以格式字符串对其进行硬编码:
printf("%.3s", str);
所以你在这里的是%.*
,它看起来像是一个带有可变精度字段的转换的开始。它将使用s
参数并将其视为int
,这是未定义的行为。
即使下一个参数实际上是一个int,接下来发生的事情是,%
变量精度之后的*
字符不是有效的转换说明符。或者,它是有效的转化说明符,是%%
转化的一部分。但编码文字%%
的{{1}}序列不支持两个字符之间的可选材料。 ISO 9899:1999(%
说明符)说“完整转换规范应为%
。”
它还说“如果转换规范无效,则行为未定义。”一个%%
规范,其中包含宽度或精度字段之间的材料,因此违反了明确规定的“完整转换规范应为%%
”的要求。
答案 1 :(得分:1)
此处,您的格式化字符串已被解释为两个部分"%.*%"
和"s"
,其中前一个是带有指定最大宽度的“转义”百分号(这就是您的{{1} }指针*
的值。请先尝试删除第二个百分号。
对不起,我想我会先为你试试,但这对我来说很不方便..
<强>编辑:强>
是的,为了得到你想要的东西你应该这样写:
s
重新编辑:
Plz check the reference manual of printf
宽度:
此处使用十进制值指定字段的宽度。如果该值不足以填充宽度,则字段的其余部分将填充空格(除非指定了0标志)。如果该值溢出字段的宽度,则扩展该字段以适合该值。如果使用*代替宽度指定符,则下一个参数(必须是int类型)指定字段的宽度。注意:当使用带宽度和/或精度说明符的*时,首先是width参数,然后是precision参数,然后是要转换的值。
YET AGAIN EDITED:
@Kaz对标准是正确的。参见ISO-IEC-9899_1990(第2版第137页):
%匹配单个%:不进行转换或分配。完全转换 规范应为%%
因此,在两个百分号之间插入任何其他转换说明符会导致未定义的行为。
答案 2 :(得分:1)
要回答您的具体问题,您的第一个printf()
语句格式不正确,因为它没有为*
修饰符提供int参数,并且对{{1}使用精度转换说明符未定义。在你的情况下,你的C实现似乎忽略了精度,所以你的print语句相当于:%
,它应该导致输出:
printf("%%s",s);
(%s
转换为输出中的%%
。
对于您的第二个%
语句,它再次格式不正确,因为您提供了无效的转换说明符,即printf()
。使用此说明符的行为会导致未定义的行为。您的系统似乎输出了错误的说明符,然后输出,
,然后处理输出您的字符串的*
。
%s
在,*hello world
中,转换说明符的printf()
修饰符是一种从*
调用的参数提供字段宽度或精度(或两者)的方式(而不是硬编码数字直接进入格式字符串本身)。所以:
printf()
将打印输出:
char *s="hello world";
int i=7;
printf("%.*s\n", i, s);
在这种情况下hello w
是精度,因为它跟随小数点。对于字符串,这表示将要打印的字符串中的最大字符数。