简体   繁体   中英

Question regarding output of printf in handling pointer to array

I was comparing various printf to better understand the difference between int * and int (*)[] and how i can visualize various addresses and values.

In the following program i wrote one thing bothers me:

#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);
}

In the first part p , as a pointer, holds as value the address of a[0] , so *p holds as value 1 ( printed with %d).

In the second part, though, q seems to hold the same value of *q (in this case i use %p), therefore i need to use **q to print b[0] .

How come?

The pointer q points to an array of 3 integers. You can visualise it like this:

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

Your print statements broken down:

  • &b - this is the base address of b .
|b = {1,2,3}| // address of whole array
  • &b[0] - this is the address of the 0th element of b .
   b = {1,2,3}
        ^
// address of b[0]
  • q - this points to the base address of b and holds the same value as &b .
q -----> |b = {1,2,3}| // address of whole array
  • *q - this will yield the address of the first element of b , in your case this is the address of b[0] .
 b = {1,2,3}
*q ---^

In regards to your question:

With q you must dereference twice ( **q ) because:

  • q points to the base address of b
  • if we dereference once ( *q ) it will yield the address of b[0] .
  • if we dereference once more ( **q ) we will get the value in b[0] .

Here is a visualization that may help you understand how it works.

- q -----> |b = {1,2,3}|  // points to base address of b
- *q ------------^ // points to address of b[0]
- **q -----------^ // value of b[0]
  • When you dereference a plain pointer like int* you get an item of type int .
  • When you dereference an array pointer like int (*q)[3] you get an array of type int [3] .

Now, whenever you use an array in an expression (in most cases) it decays into a pointer to its first element. So *q gives you an array int [3] which then immediately decays into a pointer to the first element, type int* . And that's the pointer you'll be printing. We can prove that this is the case by executing this snippet:

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

In order to print the value pointed at by that pointer, you therefore need another level of dereferencing: either (*q)[0] or **q .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM