printf()函数中格式字符串参数后的"+1"的影响

5

我有一些与此代码相关的问题。printf的参数是const char*...(可变参数列表)的类型。

1)为什么程序的输出是d而不是127
2)是不是+1会被转换成字符串并传递给类型为const char*的参数变量?

#include<stdio.h>
int main()
{
   printf("%d"+1 , 127); //how this will get executed?
   return 0;
}

输出:

d

6
"%d"+1是什么意思? - Eugene Sh.
1
问题2的答案是“绝对不是”。 - lurker
3
如果不是很明显,这是一个诡异的问题。代码不像你在真正的C程序中见过的任何代码(也许只有错误才会出现这样的代码)。它没有做任何有用的事情,只是为了让你思考;它是为了确保你准确地理解字符串的工作原理、指针的工作原理和printf函数的工作原理。如果你熟悉C语言,它的作用立即就能理解,但是如果你还不清楚,不要担心;这并不是阻碍你进步学习普通C编程的关键步骤。 - Steve Summit
你对字符串字面量后跟+1的行为感到困惑,部分原因是一些语言在字符串连接时使用“+”的方式不同,并自动将数字1强制转换为字符串“1”。具体来说,“%d”+1并不是concat(“%d”,“1”)。 - ChuckCottrill
2个回答

18

第一个参数是指向 char 的指针。
字面量 "%d" 是指向 '%' 的指针,隐含后面跟着 'd''\0'。它是指向 char 的指针,因为这是字符串字面量在C中的表示方式:以字符序列结尾为'\0'; 作为参数等表示时,使用char指针表示。
但是,根据指针算术,"%d"+1 是指向 'd',后面跟着 '\0' 的指针。
两个都以零结尾,适合作为 printf 的参数。

所以输出与…相同。

printf("d", ignored);

因为"d"告诉printf不要期望任何东西,所以它会被忽略,127会变成"ignored"。这是因为它没有任何特殊字符序列,比如"%someletter"。因此,它不期望、也不寻找任何内容,并且除了正常的字符串之外,不打印任何内容。
但需要注意的是,那些格式化字符串中没有涵盖的额外参数会在评估后被忽略。这一点很重要,因为评估的副作用(例如函数调用)实际上是会发生的。
有关详细信息,请参见:
http://en.cppreference.com/w/c/io/fprintf


1
因为 printf("d", ...) 与其后面的任何内容都没有关系。 - Eugene Sh.
1
@Goku:像 "%d" 这样的字符串常量是一个数组表达式(因为字符串被存储为数组)。在大多数情况下,数组表达式会被转换为指向该数组第一个元素的指针表达式。如果将指针加 1,则结果是指向下一个对象的指针(在此情况下为字符串的第二个字符)。因此,printf 将字符串 "d" 视为第一个参数。由于 "d" 中没有任何转换说明符,printf 不会检查任何其他参数-参数 127 将被忽略。 - John Bode
2
我可以推荐你在任何一家不错的书店翻阅几本书,看哪一本最吸引你。也就是说,翻开几页后你不想放下的那本书,就是适合你的。这里任何用户喜欢的书可能都不适合你,太贵或者送货时间太长。去书店,浏览,挑选,购买。这就是1小时的秘诀。 - Yunnosch
2
@Goku 我认为你应该更加努力地理解这个答案,它解释了你所看到的内容以及为什么参数“127”被忽略。一本好书会有所帮助,但他的答案非常针对你的问题。 - Weather Vane
2
@chux 很好的点子,任何副作用当然会在忽略之前发生,我已将其编辑到答案中。谢谢。 - Yunnosch
显示剩余5条评论

5

让我尝试帮助并补充@Yunnosch的回答,您可以做以下操作:

 char *str = "%d";
 printf (str, 127);

输出应该是:
127

在上面的例子中,str 存储在内存中像这样(这只是一个例子,在实际生活中地址会像 0xabcdef12345678):
address | memory
--------+--------------
0       | %
1       | d
3       | \0

所以str指向地址0(或等效于您的系统),该地址保存%printf()获取该地址并从那里开始读取,一直读取到NULL字符'\0'。现在每次看到%时,它都会查找下一个字符dcx等,并从参数列表中读取下一个参数。如果您提供了d,它将输出十进制数,如果您提供了c,它将打印字符,x用于十六进制,还有许多其他用途。因此,printf()将读取所有字符,并使用适当的参数替换%<place holder>,直到它遇到NULL字符\0,但它将从提供的地址开始。
您的情况:
printf("%d"+1, 127);

等同于:

char *str = "%d";
printf (str + 1, 127); // printf receives address of character `d` as starting point

或者它类似于。
char *str = "%d";
char *str1 = str+1; // increment the address of string by one
printf (str1, 127)

在这两种情况下,它都会接收d的地址,并从那里读取,直到遇到\0

如果你执行以下操作:

printf ("%d" + 2, 127);

这将与以下内容相同:

这与以下内容相同:

char *str = "%d";
printf (str + 2, 127);

如果采用printf(),它不会有任何输出,因为printf()将获取\0的地址。正如@Yunnosh所说,127将被忽略。

因此,+1+2并没有被转换为字符串,它们被添加到了字符串的地址上。

希望这可以帮到你,我想我回答了你的两个问题。


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