嗨,我有一个简单的问题
char *a="abc";
printf("%s\n",a);
int *b;
b=1;
printf("%d\n",b);
为什么第一个有效但第二个有效? 我认为第一个应该是
char *a="abc";
printf("%s\n",*a);
我认为存储“abc”的地址。那么为什么我在打印时会显示abc?我想我应该打印* a来获得它的价值。
由于
应
答案 0 :(得分:3)
为什么第一个有效但第二个无效?
因为在第一个中,你不是要求它打印一个字符,你要求它以字符串形式打印一个以空字符结尾的字符数组。
这里的混乱是你将字符串视为“本机类型”,与整数和字符的方式相同。 C不起作用;字符串只是指向以空字节结尾的一堆字符的指针。
如果您真的想将字符串视为本机类型(请记住它们确实不是),请以这种方式考虑它:字符串的类型是char *
,而不是{{1} }。因此,char
有效,因为您传递printf("%s\n", a);
以匹配指示char *
的格式说明符。要获得与第二个示例相同的问题,您需要将指针传递给字符串 - 即char *
。
或者,相当于char **
不是%d
,而是%s
,它会打印一个字符。要使用它,你做必须传递一个字符。 %c
会遇到与printf("%c\n", a)
相同的问题。
来自你的评论:
我认为存储“abc”的地址。那么为什么我在打印时会显示abc?我想我应该打印* a来获得它的价值。
这是对作为原生对象的字符串的松散思考。
当你这样写:
printf("%d\n", b)
编译器会存储一个包含四个字符的数组 - char *a = "abc";
,'a'
,'b'
和'c'
- 某处和'\0'
点在第一个,a
。只要你记得a
实际上是一个由四个独立字符组成的数组,将"abc"
视为指向该事物的指针是有意义的(至少如果你理解了数组和指针算法是如何工作的话) C)。但如果您忘记了这一点,如果您认为a
指向的是包含单个对象a
的单个地址,则会让您感到困惑。
从GNU printf
man page引用(因为C标准不可链接):
d,我
int参数转换为带符号的十进制表示法......
C
...将int参数转换为unsigned char,并生成结果字符......
取值
... const char *参数应该是指向字符类型数组(指向字符串的指针)的指针。数组中的字符被写入(但不包括)终止空字节('\ 0')...
最后一件事:
如果没有“字符串”这样的值,您可能想知道"abc"
或printf("%s", a)
或任何其他函数如何打印或搜索字符串。
他们正在使用一种约定:他们使用指向字符的指针,并从那里打印或搜索每个字符直到第一个空值。例如,您可以编写strchr(a, 'b')
函数,如下所示:
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
等函数中。
答案 1 :(得分:1)
字符串在C语言中并不是真正的“一等公民”。实际上,它们只是作为以空字符结尾的字符数组实现的,并且引入了一些语法糖以使程序员的生活更轻松。这意味着当传递字符串时,你通常会通过char *
变量来做 - 也就是指向以char
为空的终止数组的指针。
这种做法也适用于调用printf
。 %s
格式与char *
参数匹配以打印字符串 - 就像您所见。您可以使用*a
,但是您希望将其与%c
或整数格式匹配,以仅打印指向的单个字符。
出于几个原因,你的第二个例子是错误的。首先,如果没有C中的显式转换,则进行作业b = 1
是不合法的 - 您需要b = (int *)1
。其次,您正在尝试打印指针,但是您使用%d
作为格式字符串。这也是错的 - 您应该使用%p
,如下所示:printf("%p\n", (void *)b);
。
在第二个例子中你尝试的真实情况是:
int b = 1;
int *p = &b;
printf("%d\n", *p);
即,创建一个指向整数的指针,然后取消引用它并将其打印出来。
编辑说明:你应该得到一本好的初学C书(在这里搜索,我相信你会找到建议)并通过它来完成。