71

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

我知道它%c代表单个字符并%s代表一个以空字符结尾的字符串,但是单独的字符串表示还不够吗?

4

11 回答 11

99

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

char c = 'a';

在上述情况下,c必须为空终止。这是我的假设:)

于 2012-06-01T07:22:18.027 回答
74

%s打印出字符,直到它到达 a 0(或'\0',相同的东西)。

如果你只有一个, 用-char x;打印它,你必须提供地址,因为期望 a - 会产生意想不到的结果,可能不会。printf("%s", &x);%schar*&x + 10

所以你不能只打印一个字符,除非它是空终止的(非常低效)。

编辑:正如其他人指出的那样,两者在 var args 参数中期望不同的东西 - 一个是指针,另一个是单个字符。但这种差异有些明显。

于 2012-06-01T07:19:27.693 回答
38

其他人提到的单个字符必须为空终止的问题并不是真正的问题。这可以通过为格式提供精度来解决问题%.1s

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

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

明确一点:我并不是说你应该更%.1s喜欢%c. 我只是说,为什么%c不能被替代的原因与其他答案假装告诉的不同。这些其他答案在技术上是错误的。空终止不是%s.

于 2012-06-01T07:34:47.017 回答
28

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

例如

printf( "%c", ch );    tells the function the argument 'ch' 
                       is to be interpreted as a character and sizeof(char)

然而

printf( "%s", s );   tells the function the argument 's' is a pointer 
                     to a null terminated string sizeof(char*)

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

于 2012-06-01T07:45:23.450 回答
14

%s表示打印所有字符,直到找到空值(将变量视为指针)。

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

使用%sfor 字符不起作用,因为该字符将被视为指针,然后它将尝试打印内存中该位置之后的所有字符,直到找到 null

从其他答案中窃取以不同的方式解释它。

如果你想使用 打印一个字符%s,你可以使用下面的方法正确地传递一个字符的地址,并防止它在屏幕上写垃圾,直到找到一个空值。

char c = 'c';
printf('%.1s', &c);
于 2012-06-01T07:20:03.610 回答
7

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

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

如果我们使用 the%s而不是%c,我们将如何在字符之后提供 a '\0'

于 2012-06-01T07:22:14.373 回答
5

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

实际上,这归结为数据类型。我在这里看到了答案,表明您可以提供指向 char 的指针,并提供

"%.1s"

这确实可能是真的。但答案在于 C 设计者试图为程序员提供灵活性,并且确实是一种(尽管很小)减少应用程序占用空间的方法。

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

如果您想通过使用实际字符而不是指向字符的指针来减小大小,那么可以考虑在 printf 类型的运算符中执行此操作的两种方法。一个是关闭 .1s,但例程应该如何确定您真正提供的是 char 类型而不是指向 char 的指针或指向字符串(字符数组)的指针?这就是他们选择“%c”的原因,因为它是不同的。

有趣的问题:-)

于 2012-06-01T18:02:49.737 回答
2

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

Achar和字符串与 night 和 1 差不多。

于 2012-06-01T14:00:07.073 回答
2

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

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

所以你看,在引擎盖下,这两种情况虽然看起来很相似,但它们并没有太多共同之处,因为一种适用于值,另一种适用于指针。一种是将特定整数值解释为 ascii char 的指令,另一种是逐个 char 迭代内存位置 char 的内容并解释它们直到遇到零值。

于 2012-06-05T19:08:19.707 回答
2

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

    #include<stdio.h>
    int main(){
        char c = 'a';
        int i;
        for(i = 0; i < 40000000; i++){
            //printf("%.1s", &c); get a result of 4.3s
            //printf("%c", c); get a result of 0.67s
        }
        return 0;
    }

结果表明 using比 .%c快 10 倍%.1s。因此,尽管 %s 可以完成 %c 的工作,但性能仍然需要 %c。

于 2012-06-06T16:47:03.873 回答
1

由于没有人提供任何参考的答案,这里有一个来自pubs.opengroup.com的 printf 规范,它类似于IBM的格式定义

%C

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

%s

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

于 2012-06-05T18:42:51.790 回答