为什么第一个有效,第二个无效?
因为首先,您不是要求它打印一个字符,而是要求它打印一个以 null 结尾的字符数组作为字符串。
这里的混淆在于您将字符串视为“本机类型”,就像整数和字符一样。 C 不能那样工作;字符串只是指向以空字节结尾的一堆字符的指针。
如果您真的想将字符串视为本机类型(请记住它们确实不是),请这样想:字符串的类型是char *,而不是char。因此,printf("%s\n", a); 有效,因为您传递了 char * 以匹配指示 char * 的格式说明符。要获得与第二个示例相同的问题,您需要传递一个指向字符串的指针,即 char **。
另外,%d 的等价物不是%s,而是%c,它打印单个字符。要使用它,您确实必须向它传递一个字符。 printf("%c\n", a) 会出现与printf("%d\n", b) 相同的问题。
来自您的评论:
我认为 a 存储“abc”的地址。那么为什么当我打印 a 时它显示 abc 呢?我想我应该打印 *a 来获得它的价值。
这就是将字符串视为原生对象的松散想法失败的地方。
当你写这个时:
char *a = "abc";
编译器会在某处存储一个由四个字符组成的数组——'a'、'b'、'c' 和'\0',而a 指向第一个字符a。只要您记得"abc" 实际上是一个由四个独立字符组成的数组,就可以将a 视为指向该事物的指针(至少如果您了解数组和指针运算在C 中的工作原理)。但是,如果您忘记了这一点,如果您认为 a 指向一个包含单个对象 "abc" 的单个地址,那么您会感到困惑。
引用GNU printf man page(因为 C 标准不可链接):
d, 我
int 参数被转换为有符号十进制表示法……
c
... int 参数被转换为无符号字符,并写入生成的字符...
s
... const char * 参数应该是指向字符类型数组的指针(指向字符串的指针)。数组中的字符最多写入(但不包括)一个终止空字节('\0')……
最后一件事:
您可能想知道printf("%s", a) 或strchr(a, 'b') 或任何其他函数如何在没有“字符串”这样的值时打印或搜索字符串。
他们使用了一个约定:他们获取一个指向字符的指针,然后打印或搜索从那里到第一个 null 的每个字符。例如,您可以像这样编写print_string 函数:
void print_string(char *string) {
while (*string) {
printf("%c", *string);
++string;
}
}
或者:
void print_string(char *string) {
for (int i=0; string[i]; ++i) {
printf("%c", string[i]);
}
}
无论哪种方式,您都假设 char * 是指向字符数组开头的指针,而不仅仅是指向单个字符,并打印数组中的每个字符,直到您遇到空字符。这就是“以空字符结尾的字符串”约定,在整个标准库中都融入了 printf、strstr 等函数。