【问题标题】:Use of * in a printf statement在 printf 语句中使用 *
【发布时间】:2013-07-16 09:37:33
【问题描述】:

谁能解释一下这些输出背后的逻辑?我猜这里* 被用作抑制字符,但我无法弄清楚输出。

main()
{
char *s="hello world";
int i=7;
printf("%.*%s",s);
}

输出:%s

如果您将 printf 语句替换为 printf("%,*%s",s),那么您的输出将是 ,*hello world???

【问题讨论】:

  • 你的问题是scanf,但你的代码是printf。是哪个?
  • 对不起,我写错了scanf,应该是printf。我已经编辑过了。

标签: c


【解决方案1】:

printf 格式字符串"%.*%s" 无效。 * 字符不被视为转换抑制说明符,而是作为指定精度的 . 字符的参数。

与类似的比较:

printf("%.*s", 3, str);

* 将下一个参数 (3) 作为精度字段(对字符串具有特殊含义),然后 s 采用字符串。由于3 是一个常量,这相当于将其硬编码为格式字符串:

printf("%.3s", str);

所以你在这里看到的是%.*,它看起来像是带有可变精度字段的转换的开始。它将使用s 参数并将其视为int,这是未定义的行为。

即使下一个参数实际上是一个 int,那么接下来会发生的是 % 跟在 * 变量精度后面的字符不是有效的转换说明符。或者,它是一个有效的转换说明符,作为%% 转换的一部分。但是用于编码文字%%% 序列不支持两个字符之间的可选材料。 ISO 9899:1999 说(% 说明符)“完整的转换规范应为%%。”

它还说“如果转换规范无效,则行为未定义。” %% 规范,其中您在其间有诸如宽度或精度字段之类的材料,是无效的,因为它违反了明确规定的要求,即“完整的转换规范应为 %%”。

【讨论】:

  • 好吧,但我不认为像"%.*%s" 这样的格式字符串是无效,这不是人们通常想要的,但它完全兼容 b> 符合 ANSI C 标准。抱歉,我暂时找不到这是在哪个部分指定的。
  • 我的 ISO9899:1999 副本说“如果转换规范无效,则行为未定义”。摸索格式字符串的后果是严重的。 :)
  • 是的,你是对的,请检查我的答案更新。 :D
【解决方案2】:

要回答您的具体问题,您的第一个 printf() 语句格式不正确,因为它没有为 * 修饰符提供 int 参数,并且未定义对 % 转换说明符的精度使用。在您的情况下,您的 C 实现似乎忽略了精度,因此您的打印语句相当于:printf("%%s",s);,这应该会导致输出:

%s

%% 在输出中转换为%)。

对于您的第二个printf() 语句,它又是格式错误的,因为您提供了无效的转换说明符,即,。使用此说明符的行为会导致未定义的行为。您的系统似乎输出了错误的说明符,然后输出了*,然后处理了输出您的字符串的%s

,*hello world

printf() 中,转换说明符的* 修饰符是一种从printf() 调用的参数中提供字段宽度或精度(或两者)的方式(而不是将硬编码数字直接转换为格式字符串本身)。所以:

char *s="hello world";
int i=7;
printf("%.*s\n", i, s);

将打印输出:

hello w

在这种情况下,* 是精度,因为它跟在小数点后面。对于字符串,这意味着将要打印的字符串中的最大字符数。

【讨论】:

  • 是的,终于明白了。谢谢
【解决方案3】:

在这里,您的格式化字符串已被解释为两部分 "%.*%""s",其中前者是具有指定最大宽度的“转义”百分号(这就是您的 * 所做的),其值为指针s。尝试先删除第二个百分号。

对不起,我想我先给你试试这个,但目前对我来说不方便..

已编辑:

是的,要得到你想要的,你应该这样写:

// here width is a customized value you pass to specify the maximum width of string 
printf("%.*s", width, s); 

// and this would give "hello worl" as its output. notice the missing "d"
printf("%.*s", 10, s); 

再次编辑:

请检查the reference manual of printf

宽度:
此处使用十进制值指定字段的宽度。如果该值不足以填充宽度,则该字段的其余部分用空格填充(除非指定了 0 标志)。如果值溢出字段的宽度,则扩展字段以适合该值。如果使用 * 代替宽度说明符,则下一个参数(必须是 int 类型)指定字段的宽度。注意:当使用带宽度和/或精度说明符的 * 时,首先是宽度参数,然后是精度参数,然后是要转换的值。

再次编辑:

@Kaz 对标准的看法是正确的。请参阅 ISO-IEC-9899_1990(第 2 版第 137 页):

% 匹配单个 %:不发生转换或赋值。完整的转换 规格应为 %%

因此在两个百分号之间插入任何其他转换说明符会导致未定义的行为。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-19
    • 1970-01-01
    相关资源
    最近更新 更多