【问题标题】:Question regarding output of printf in handling pointer to array关于 printf 在处理指向数组的指针时输出的问题
【发布时间】:2022-08-18 00:42:55
【问题描述】:

我正在比较各种printf,以更好地了解int *int (*)[] 之间的区别以及我如何可视化各种地址和值。

在下面的程序中,我写了一件让我烦恼的事情:

#include <stdio.h>
    
int main() {
    int a[3] = {1,2,3};
    int *p = a;                             
    
    printf(\"address of a:  %p\\n\", &a);
    printf(\"\\naddress of a[0]:  %p\\n\", &a[0]);
    printf(\"\\nvalue of p:  %p\\n\", p);
    printf(\"\\nvalue of *p:  %d\\n\", *p);
    printf(\"\\nvalue of a[1]:  %d\\n\", *(p + 1));
    
    puts(\"\\n\\n-------------------\\n\\n\");
    
    int b[3] = {1,2,3};
    int (*q)[3] = &b;
    
    printf(\"address of b:  %p\\n\", &b);
    printf(\"\\naddress of b[0]:  %p\\n\", &b[0]);
    printf(\"\\nvalue of q:  %p\\n\", q);
    printf(\"\\nvalue of *q:  %p\\n\", *q);
}

在第一部分中,p 作为一个指针,将a[0] 的地址保存为值,因此*p 保存为值1(用 %d 打印)。

不过,在第二部分中,q 似乎拥有与*q 相同的值(在这种情况下我使用 %p),因此我需要使用**q 来打印b[0]

怎么来的?

  • 数组和它的第一个元素的地址相同,但对应的指针类型不同。
  • \"so *p 作为值 1\"... 不,*p 指向值(恰好是 1)...p 是一个变量,其数据类型为 pointer to int 意味着 p 可以保存一个内存地址(指向),在这种情况下,一个int...我希望这会有所帮助...
  • 作为奖励,与p + 1 相比,您还可以观察q + 1(不是*(q + 1),请注意)的值。请注意,在使用%p 时,您应该转换为void *
  • int *p = a;int *p = &amp;a[ 0 ]; 完全相同(简写)也许看到这一点会更加明显,p 被分配了a[ ] 的第一个元素的地址...
  • @Lundin 是的,你是对的。谢谢你的纠正

标签: c pointers


【解决方案1】:
  • 当你取消引用像int* 这样的普通指针时,你会得到一个int 类型的项目。
  • 当您取消引用int (*q)[3] 之类的数组指针时,您会得到一个int [3] 类型的数组。

现在,每当您在表达式中使用数组时(在大多数情况下),它都会衰减为指向其第一个元素的指针。所以*q 给你一个数组int [3],然后它立即衰减为指向第一个元素的指针,类型为int*。这就是您要打印的指针。我们可以通过执行这个 sn-p 来证明是这样的:

_Generic(*q, 
         int*:      puts("we ended up with an int*"), 
         int(*)[3]: puts("this wont get printed") );

为了打印该指针指向的值,您需要另一个级别的取消引用:(*q)[0]**q

【讨论】:

  • 我明白了,这也是我需要为b[1] 而不是*(q + 1)*(*q + 1) 的原因,对吗?
  • @Talete 有点,是的。在*q + 1 的情况下,指针运算在int* 类型上执行,但在q + 1 的情况下,它在int (*)[3] 类型上执行,在后一种情况下+1 表示+整个int [3] 数组的大小.
【解决方案2】:

数组q 指向一个由 3 个整数组成的数组。你可以像这样可视化它:

                 
  q -----> |b = {1,2,3}|
                
 
// q points to the whole array.
// note how it doesn't point to a specific element.

您的打印语句细分:

  • &amp;b - 这是b 的基地址。
|b = {1,2,3}| // address of whole array
  • &amp;b[0] - 这是b0th 元素的地址。
   b = {1,2,3}
        ^
// address of b[0]
  • q 保存b 的基地址,并保存与&amp;b 相同的值。
q -----> |b = {1,2,3}| // address of whole array
  • *q 这将产生b 的第一个元素的地址,在您的情况下这是b[0] 的地址。
 b = {1,2,3}
*q ---^

对于 q,您必须取消引用两次 (**q),因为:

  • q 指向整个数组 b
  • 如果我们取消引用一次 (*q),它将产生b[0] 的地址。
  • 如果我们再次取消引用 (**q),我们将获得 b[0] 中的值。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-10-10
    • 1970-01-01
    • 2021-04-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多