为什么C的printf格式字符串同时具有%c和%s?


71

为什么C的printf格式字符串同时具有%c%s

我知道它%c代表一个字符并%s代表一个以空值结尾的字符串,但是仅字符串表示就够了吗?


50
可能区分以null结尾的字符串和字符。如果他们只有%s,那么每个字符都必须以null结尾。char c ='a'; ,在这种情况下c必须以null结尾。不过,这是我的假设:)
Mahesh 2012年

23
@Mahesh:为什么不把它作为答案,尤其是当它成为答案时
Alok保存

4
??如果您只想输入一个字符,为什么要在该字符后附加一个NUL呢?还是在这个问题上我没有得到什么?
Christian Rau 2012年

2
@Mahesh,您的假设是我相信这个问题的答案
Krishnabhadra

1
%c需要一个char类型的数据-一个值原语。%s需要一个数据char *类型的指针。尽管它们都适用于文本,但两者之间的差异在C中是巨大的。
罗素·博罗戈夫

Answers:


99

可能区分以null结尾的字符串和字符。如果他们只有%s,那么每个字符都必须以null结尾。

在上述情况下,c必须以null终止。虽然这是我的假设:)


13
这不是真正的答案,因为可以避免这种情况%.1s
詹斯·古斯特

3
@Merlin我没那么说。可能我的句子结构可能令人困惑。您可能知道,格式说明符的格式字符串%s必须为null终止。如果没有%c该语言,那么在我上面的示例中,标识符c必须以null终止,以便能够与格式说明符一起使用%s
Mahesh 2012年

7
@mahesh令人困惑的答案比给出错误的答案更糟糕……我不敢相信您在争论这个问题。
Moog 2012年

40
-1这是一个很差的答案...之所以printf("%s", c)不起作用,不是因为终止为空,而是因为printf期望%s指向一个内存位置,而cis是一个字符值。空终止printf("%s", &c)不起作用的原因,但是即使这样,具有%c标识符仍然有意义,因为要求&c与其他所有变量类型的打印方式不一致。因此,仅说“这是因为终止终止”是不正确的。
BlueRaja-Danny Pflughoeft 2012年

9
我看不到有74个人认为这是正确的答案,因为它没有提到您甚至必须传递achar*来获得要打印的一个字符%s。只是重申BlueRaja所说的-Juan
Mendes

74

%s打印出字符,直到到达一个0(或'\0'相同的东西)为止。

如果只有a char x;,则用printf("%s", &x);-进行打印(您必须提供地址,因为%s期望achar*)会产生意想不到的结果,而&x + 1可能不会0

因此,您不能只打印单个字符,除非该字符以空字符结尾(非常无效)。

编辑:正如其他人指出的,两者在var args参数中期望不同的东西-一个是指针,另一个是单个char。但是这种区别是显而易见的。


8
您应该提到%s带指针而%c带字符本身。
马特

而且更重要的是,只有可以使用字符的地址才能打印字符。那将排除打印函数的返回值,例如,也不注册变量。
詹斯·古斯特

1
您可以通过提供精度来避免空终止的问题。
詹斯·古斯特

38

其他人提到的一个字符必须以null结尾的问题并不是一个真正的问题。这可以通过提供一种精确的格式来解决%.1s

我认为更重要的是,对于%s任何形式的内容,您都必须提供一个或多个字符的指针。这意味着您将无法打印右值(计算表达式,函数返回等)或注册变量。

编辑:我对这个答案的反应真的很生气,所以我可能会删除它,这确实不值得。似乎人们对此做出了反应,甚至没有阅读问题或不知道如何理解问题的技术性。

明确说明:我并不是说您应该优先%.1s%c。我只说%c不能用其他理由代替的理由与其他答案不同。这些其他答案在技术上只是错误的。空终止不是的问题%s


5
@LuchianGrigore:不,相反,我不是说任何人都应该喜欢它。我说那%.1s将具有仅打印一个甚至都不为null终止的字符的功能,因此null终止不是对“ introduce”的有效反对%c
詹斯·古斯特

4
@Als会%.1s期待achar或achar*吗?
Luchian Grigore'1

2
@LuchianGrigore,没人这么说。我的回答只是指出,空终止不是正确的参数,而采用对象的地址是一个参数。
詹斯·古斯特

3
@JoshuaDrake,您读了我的答案吗?我觉得那件事实在太过分了。我并不是说任何人都应该使用%.1s该字符来打印字符。这不是问题。问题是是否%c严格必要。我对此表示肯定的回答,只是说说原因与其他答案中给出的原因不同。
詹斯·古斯特

3
@JoshuaDrake:-1未读答案。这个问题问X为什么在C中存在,并且这个答案清楚地说明X必须存在才能使用右值。如果不考虑右值,那么语言/库设计人员可能(也应该应该)将其保留在%.1s处,因为它使printf更整洁(因此adn更具可读性)。如果没有c,则打印返回单个字符的函数的结果可能会变得非常复杂(尤其是如果调用具有副作用且依赖于顺序的多个函数时)。
jmoreno 2012年

28

printf函数是可变参数函数,这意味着它具有可变数量的参数。在调用函数(printf)之前,将参数压入堆栈。为了使函数printf使用堆栈,它需要知道有关堆栈中内容的信息,为此使用了格式字符串。

例如

在printf函数内部无法以其他方式确定堆栈内容,例如,区分“ ch”和“ s”,因为在C中,运行时不进行类型检查。


9
但是您的sizeof规格完全错误。首先,ch被提升为int(或在某些平台上为unsigned)并将其printf解释int为字符。因此,“在堆栈上”该参数的大小为sizeof(int)。第二秒钟你又错了,没错sizeof(char*)sizeof(int)可以(现在经常)与此不同。第三,没有必要涉及“堆栈”之类的东西。这些参数的传递方式由平台ABI自行决定,一切都可能在寄存器中发生。
詹斯·古斯特

2
@AndersK:“在技术上” Jens是完全正确的。实际上,您最好删除“技术上”一词;他说得很对。
基思·汤普森

1
“有些错误有时会节省大量的解释” –赫克托·休·芒罗
AndersK 2012年

14

%s 说打印所有字符,直到找到空(将变量作为指针处理)。

%c 说只打印一个字符(将变量作为字符代码处理)

使用%s的字符不工作,因为性格会像一个指针来处理,那么它会尝试打印以下所有内存中发生的字符,直到它找到一个空

偷走其他答案,以不同的方式进行解释。

如果您想使用来打印字符%s,则可以使用以下代码正确地将其传递给char地址,并防止其在屏幕上写入垃圾,直到找到空值为止。


1
这并非完全正确。对字符使用%s可以做完全出乎意料的事情,因为它将字符解释为指向字符的指针,这很可能指向无效位置。
马特

为了清楚起见(因为很多人混淆了这些概念),字符串以空字符结尾,而不是与空指针混淆。
基思·汤普森

@KeithThompson只是让人们感到困惑:空字符'\0'和空指针都在内部表示为0:)
Juan Mendes 2012年

2
@JuanMendes:不,它们都可以在源代码中表示为0。它们的内部表示形式可以完全不同。空字符通常为8位,而空指针通常为32或64位。此外,一个空指针的内部表示并不一定是所有位归零(虽然它很常用的)。
基思·汤普森

1
@Keith有问题的语言是C,而且我从未听说过内部表示形式不是0。这就是为什么您可以使用以下任何一种方式的原因。if (pointer)if (pointer != 0 )if(pointer != NULL )另外,我认为使用8、16、32位的0差别不大。bytes.com/topic/c/answers/213647-null-c
Juan Mendes

7

对于%s,我们需要提供字符串的地址,而不是其值。

对于%c,我们提供字符的值。

如果我们使用%s代替%c,我们将如何'\0'在字符后提供a ?


5

我想为这个有趣的问题添加另一个观点。

确实,这归结于数据类型。我在这里看到的答案是,您可以提供一个指向char的指针,并提供一个

的确是这样。但是答案在于C设计人员试图为程序员提供灵活性,并且确实是(虽然很小)减少应用程序占用空间的方法。

有时,程序员可能希望运行一系列if-else语句或切换用例,其中需要根据状态简单地输出字符。为此,硬编码字符确实可以占用较少的实际内存空间,因为单个字符为8位,而指针为32或64位(对于64位计算机)。指针将占用更多的内存空间。

如果您想通过使用实际的char与指向char的指针来减小大小,则可以在printf类型的运算符中采用两种方法来做到这一点。一种方法是从.1开始,但是例程应该如何确定您确实在提供一个char类型与一个char指针或一个字符串(char数组)的指针呢?这就是为什么他们使用“%c”的原因,因为它有所不同。

好玩的问题:-)


2

C具有%c%s格式说明符,因为它们处理不同的类型。

Achar和一个字符串与Night和1差不多一样。


正如您提到的,%s和%c完全不同,然后请告诉我为什么 scanf(%s, &ch)andscanf(%c, &ch) 语句返回相同的结果。考虑到ch是一个类似char的字符char ch
维杰·普拉塔普王子(Vijay Pratap)2016年

2

%c需要一个char,它是一个整数值,并根据编码规则将其打印出来。

%s需要一个指向包含char值的内存位置的指针,并根据编码规则在该位置打印字符,直到找到0(空)字符为止。

因此,您会发现,在幕后的情况下,这两种情况看起来很相似,它们之间没有太多共同点,因为一种情况下使用值,而另一种情况下使用指针。一种是用于将特定整数值解释为ascii char的指令,另一种是通过char迭代存储位置char的内容并将其解释为遇到零值的指令。


2

我已经用printf("%.1s", &c)和进行了实验printf("%c", c)。我使用下面的代码进行测试,并使用bash的time实用程序来获取运行时间。

结果表明,使用%c速度是的10倍%.1s。因此,尽管%s可以完成%c的工作,但仍需要%c来提高性能。


1

由于没有人提供任何参考答案,因此这是pubs.opengroup.com的printf规范,它与IBM的格式定义相似。

%C

将int参数转换为无符号字符,并写入结果字节。

%s

该参数应为指向char数组的指针。数组中的字节应写入(但不包括)任何终止的空字节。如果指定了精度,则最多只能写入多个字节。如果未指定精度或大于数组的大小,则应用程序应确保数组包含一个空字节。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.