【问题标题】:pointer of char and intchar 和 int 的指针
【发布时间】:2013-06-02 21:33:17
【问题描述】:

您好,我有一个简单的问题

char *a="abc";
printf("%s\n",a);

int *b;
b=1;
printf("%d\n",b);

为什么第一个有效,第二个无效? 我觉得第一个应该是

char *a="abc";
printf("%s\n",*a);

我认为 a 存储“abc”的地址。那么为什么当我打印 a 时它显示 abc 呢?我想我应该打印 *a 来获得它的价值。

谢谢

【问题讨论】:

  • 我确定这是一个骗局(可能多次重复),但无论如何,你应该阅读c-faq.com/charstring/index.html
  • 另外,您阅读过printf 手册页吗?它准确地描述了需要什么以及如何使用它。
  • 请尝试在启用警告的情况下进行编译。
  • 你能引用地址 1 吗..它不是正确的地址..而“abc”返回存储“abc”的地址
  • 大多数printf 格式说明符使用相应参数的%s 的不寻常之处在于它使用了参数指向的内容。

标签: c pointers char int


【解决方案1】:

字符串在 C 中并不是真正的“一等公民”。实际上,它们只是实现为以空字符结尾的字符数组,并添加了一些语法糖以使程序员的生活更轻松。这意味着在传递字符串时,您将主要通过 char * 变量来执行此操作 - 即指向以空结尾的 char 数组的指针。

这种做法也适用于拨打printf%s 格式与 char * 参数匹配以打印字符串 - 正如您所见。您可以使用*a,但您希望将其与%c 或整数格式相匹配,以仅打印指向的单个字符。

由于几个原因,您的第二个示例是错误的。首先,在 C 中没有显式转换的情况下进行赋值 b = 1 是不合法的 - 你需要 b = (int *)1。其次,您试图打印出一个指针,但您使用 %d 作为格式字符串。这也是错误的 - 你应该像这样使用%pprintf("%p\n", (void *)b);

在第二个示例中,您真正尝试做的是:

int b = 1;
int *p = &b;
printf("%d\n", *p);

也就是说,创建一个指向整数的指针,然后取消引用并打印出来。

编者注:你应该得到一本很好的初学者 C 书(在这里搜索,我相信你会找到建议)并完成它。

【讨论】:

  • 当使用 CHAR 指针时 P = 整个字符串 &P = 指针地址 *P = 字符串的第一个块 *(P + 2) = 使用 INT 指针时的字符串的第三块 P = 地址P 指向的内容 &P = 指针本身的地址(INT *P 的地址)*P = 指针的内容(1 个内存块)
  • 天哪,有很多大写字母。我不确定你在问什么。您是否阅读了我在上面的评论中发布的常见问题解答链接?在这种情况下,您所说的“阻止”是什么意思?你是想说“字节”吗?
  • 我知道关于int指针的解决方案。所以对于 a 的 char 指针。什么存储在 *a 中,什么存储在 a 中?我认为 *a 应该存储“abc”;
  • @saul203:你告诉编译器a 是一个char *——一个指向字符的指针。所以,*a必须是一个字符。它是;这是'a'printf 可以打印 abc 而不仅仅是 a 的原因是它遵循以 null 结尾的字符串约定:要打印 %s,它会打印 a 处的字符,然后是 a+1 处的字符,依此类推,一旦找到空字符就停止。
【解决方案2】:

为什么第一个有效,第二个无效?

因为首先,您不是要求它打印一个字符,而是要求它打印一个以 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 * 是指向字符数组开头的指针,而不仅仅是指向单个字符,并打印数组中的每个字符,直到您遇到空字符。这就是“以空字符结尾的字符串”约定,在整个标准库中都融入了 printfstrstr 等函数。

【讨论】:

  • 这是正确的吗?使用 CHAR 指针时 P = 整个字符串 &P = 指针地址 *P = 字符串的第一个块 *(P + 2) = 字符串的第三块 使用 INT 指针时 P = 内容地址 P 指向 &P =指针本身的地址(INT *P 的地址)*P = 指针的内容(1 块内存)
  • 在大写字母和缺乏格式之间,这很难阅读——但即使我读懂了,我也不明白你的问题是什么。但是如果你写的是P = "abcd";,那么P是一个指向初始'a'的指针,按照惯例,一些函数将用作指向以'a'开头并以第一个结尾的字符串的指针空字符('d' 之后)。
  • 所以,*P'a'&P 是指向 'a' 的指针,P+2 是指向 'c' 的指针(可以传递给字符串函数,它会将其视为字符串"cd"),*(P+2)'c'
  • 谢谢,但我的意思是如果 char *p="abcd" 然后 print p i 可以得到“abcd”。但是打印 *p 呢?
  • 当我用 %c 打印 p 时。我得到一个“?”。我不知道这是怎么发生的
猜你喜欢
  • 2017-09-03
  • 1970-01-01
  • 1970-01-01
  • 2017-02-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-18
相关资源
最近更新 更多