【问题标题】:Printing values, pointers and pointers to values [closed]打印值、指针和指向值的指针[关闭]
【发布时间】:2018-10-03 13:41:04
【问题描述】:
#include<stdio.h>
int main()
{   int i;
    int *p;
    p = &i;
    i=5;

    printf("i = %d, p = %P, *p = %d\n",i,p,*p);

    *p=6;
    printf("i = %d, p = %P, *p = %d\n",i,p,*p);

    return 0;
}

这段代码的输出是:

i = 5, p = %P, *p = -1009882308
i = 6, p = %P, *p = -1009882308

它应该在第一个语句和第二个语句中给出 *p=5 的位置 *p=6

【问题讨论】:

  • 首先,我建议将%P 替换为%p。 P 格式说明符不存在。
  • 我很惊讶你的编译器没有警告你有比说明符更多的“对象”。像我上面所说的那样替换格式说明符,您的问题应该得到解决。
  • 查看this answer 了解为什么没有编译错误/警告。
  • @Tau 是的,我的编译器对 %P 发出了警告,但如果我们不关注它,那么对于 *p 它也应该返回 i 的值,即 5 然后 6
  • 您似乎忘记启用一组好的警告。对于 GCC,我建议至少 -Wall -Wextra -Wwrite-strings;还可以考虑使用-Wpedantic -Warray-bounds 来识别其他一些常见错误。

标签: c pointers printf


【解决方案1】:

在您的 printf 中,您尝试显示 p = %P 或 %P 不存在,因此 %P 将被忽略并像字符串一样打印。

之后,当您尝试打印*p = %d 时,您不会打印变量*p,而是打印p,因为p 没有被%P 使用。

正确的 printf 应该是:

printf("i = %d, *p = %d\n",i,*p);

【讨论】:

  • 能否解释一下最后一行
  • 在 printf printf("i = %d, p = %P, *p = %d\n",i,p,*p); 你有一个 %d、一个 %P 和另一个 %d。以及三个变量:i、p、*p。所以 printf 将首先显示 %d 及其对应的变量 (i),在 printf 将忽略 %P 之后(因为 %P 没有退出),最后 printf 将打印 %d 对应的变量 (p) 因为 (p ) 尚未被 %P 使用。最后一个变量 (*p) 未使用。要使用 (*p),您必须删除 printf 中的变量 (p)。
  • "因此 %P 将被忽略并像字符串一样打印。" --> "%P will be ignored ..." 只是一种可能性。由于"%P" 不是指定的打印说明符,结果是未定义的行为 (UB)。
【解决方案2】:

您已将以下字符串指定为printf() 的格式化字符串:

i = %d, p = %P, *p = %d

然后你指定三个要打印的元素:

i, p, *p

因此,%d 被替换为存储在i 中的值,正如预期的那样:

i = 5, p = %P, *p = %d

到目前为止一切顺利,除了一件事:%P 格式 不存在。因此,它作为说明符被跳过并被打印出来。

然后第二个%d 被替换为p 中的值,不是 *p,因为第二个%d 是下一个有效的说明符,p 是下一个要使用的变量:

i = 5, p = %P, *p = -1009882308

由于没有更多的说明符可供使用,*p 被忽略,编译时会抛出警告或错误。

恭喜,您刚刚将p 指向的地址打印为int,即未定义行为。

那么,我们该如何补救呢?

将%P 替换为实际有效的说明符:%p。现在所有变量和说明符都被使用了,你的代码将顺利运行。

这是printf() 应该打印的内容:

i = 5, p = C3CE6B3C, *p = 5

注意:使用%p打印p的地址,将打印为十六进制数。

编辑:正如chux所说,%p 需要相应的void* 才能按预期工作。在printf() 语句中将p 转换为(void*),如下所示:(void*)p

【讨论】:

  • 详细信息:“*p 被忽略,编译时会抛出警告或错误。” --> printf() 中的额外参数是可以的。 C 被很好地指定来处理这个问题。然而,一些编译器会发出警告(通常是编码错误),而一些编译器选项将所有警告视为错误。
  • "%p" 匹配 void*,p 是 int*。不匹配是UB。最好使用"%p" 和(void*)p。
  • 注意到了。我编辑了帖子。
【解决方案3】:

您的格式说明符有错字,无法识别。结果,您将要作为整数打印的指针传递。应该是这样的:

printf("i = %d, p = %p, *p = %d\n",i,p,*p);

大多数编译器都会对您的代码发出警告。如果您没有,请检查您是否可以将设置更改为更严格的警告。

【讨论】:

  • 是的,我的编译器对 %P 发出了警告,但如果我们不关注这一点,那么对于 *p 它也应该返回值 i,即 5,然后是 6
  • @deep_purohit 当你搞砸了 %P 时,不能保证打印 *p 会按照你的预期工作。编码错误可能会产生后果,例如一个地方的错误会使另一个地方的代码做出意想不到的事情,在这种情况下,它会产生严重的后果。
  • @deep_purohit 因为%P 不是一个有效的格式说明符,p 这是%d 使用的第二个参数。使用%d 打印地址会给你带来奇怪的结果。
  • "%p" 需要 void*,而不仅仅是任何指针。
  • @deep_purohit:永远不要忽略警告 - 这个特定的警告与您看到错误输出的原因有关。
【解决方案4】:

为什么下面的 C 代码的输出是这样的?
是的,我的编译器对 %P 发出了警告,但如果我们不关注它,那么对于 *p 它也应该返回 i 的值,即 5 和 6 comment。

关键问题是假设警告后的代码应该表现良好。

该警告是由于使用了无效的打印说明符 "%P" 而导致的。这会导致未定义的行为 (UB)。其余代码不再具有任何指定的行为。因此 C 不支持“应该返回 i 的值,即 5 然后 6”。输出可以是任何东西。


使用有效的打印说明符和匹配的参数。

使用"%p" 打印void*。要将 p 转换为 void*,请应用强制转换。

// printf("i = %d, p = %P, *p = %d\n",i,p,*p);
printf("i = %d, p = %p, *p = %d\n", i, (void*)p, *p);

【讨论】:

    【解决方案5】:

    %P 不是一个有效的转换说明符,因此您的第二个参数p 被打印为带有%d 的十进制整数,而*p 根本没有被打印。

    将两行改为

    printf("i = %d, p = %p, *p = %d\n",i, (void *)p,*p);
                         ^
                         |
                         +---- note lower case p here
    

    你会得到你期望的输出。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-27
      • 2019-08-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多