Hritik
Hritik

Reputation: 722

Pointer pointing to itself

I was exploring typedefs and stumbled upon this program

EDIT: Nearly all the answers were concerned about the warnings it generates. So, I went ahead and removed all the warnings but the question remains the same.

#include<stdio.h>
typedef int int3[3];
int main(){
    int a[2][3] = {{1,2,3}, {4,5}};
    int3 *p = a;
    int *ip = (int *) a;
    printf("sizeof:\np: %lu\n(*p+0): %lu\n**p: %lu\nip: %lu\n*ip: %lu\n",sizeof p, sizeof (*p+0), sizeof **p, sizeof ip, sizeof *ip);
    printf("---\n");
    printf("p: %p\tp+1: %p\n*p: %p\t*p+1: %p\n**p: %d\nip: %p\n*ip: %d",p,p+1,*p,*p+1,**p,ip,*ip);
    return 0;
}

on one run it shows:

sizeof:
p: 8
(*p+0): 8
**p: 4
ip: 8
*ip: 4
---
p: 0x7ffe36df31b0   p+1: 0x7ffe36df31bc
*p: 0x7ffe36df31b0  *p+1: 0x7ffe36df31b4
**p: 1
ip: 0x7ffe36df31b0
*ip: 1

My question is: If p and *p are equal
and **p = 1
then why not *p = 1 as well ?

Provided size of pointer = 8 and size of int = 4
Even if taking in account pointer arithmetic, then *p should at least be 0xkk kk kk kk 00 00 00 01
k being any hex number (consider little-endian)
because de-referencing the same address as int should give 1

EDIT: To make things clearer, consider this table:

+-----------+----------------------+------------------+
|Variable   | Value                | Address          |
|           |                      |                  |
|           |                      |                  |
| p         | 0x7ffe36df31b0       |                  |
|           |                      |                  |
|*p         | 0x7ffe36df31b0       |  0x7ffe36df31b0  |
|           |                      |                  |
|**p        | 1                    |  0x7ffe36df31b0  |
+-----------+----------------------+------------------+

How can *p and **p have same address but different value ?

Upvotes: 0

Views: 192

Answers (3)

Andrew Henle
Andrew Henle

Reputation: 1

First, note that this code in a confusing mish-mash of constraint violations combined with array decay to generate output of questionable usefulness. But I'll try to answer your question as to what's going on, and try using mundane explanations without resorting to citations from the C Standard, as others already have answered in that manner.

How can *p and **p have same address but different value ?

Because p is a pointer to an array.

Given

typedef int int3[3];
int3 *p;

that means *p is a three-dimensional array. Note that

int3 *p = a;

is a constraint violation, as noted elsewhere. You can force that to "work" with a cast, but it's still fundamentally wrong and the code only "gets away" with it because the address of an array is the address of the first element of that array - and your current implementation doesn't differentiate the pointer types in a significant-enough fashion they they're fundamentally incompatible. Pick an implementation where a plain int * is, say, a 32-bit offset value while an array would have as its address both a 32-bit segment and a 32-bit offset value, and the code would likely generate nonsense if it didn't fail utterly. That's why the C Standard requires pointers to be to "compatible types" - because pointers don't have to be compatible at all.

That problem aside, the initialization/assignment on your implementation can seemingly be treated as

int3 *p = ( int3 * ) a;

Since that "works", that means p contains the address of a three-element array of int values. So dereferencing p with *p is the same as a[0], or the first three-element int array in the two-dimensional a array.

So what is *p, then?

It's exactly the same in this case as a[0], an array. And such a bare array reference decays to an address*, and that address is of the same type as a pointer to an element of the array. And the value of that address will be that of the address of the first element of the array.

So *p, which is a three-element array of int, can itself be dereferenced and evaluate to the first element of a[0], or a[0][0]. So **p is the same as a[0][0].

And a[0][0] - or **p - is an int that is initialized with the value of 1.

While *p is a[0] and the address of that first element.

* - A lot of people say an array "decays to a pointer" or "an array is a pointer", but I like "decays to an address" because a pointer can be assigned to but an address simply is - it can't be assigned to itself, just like an array itself can't be assigned to, but the address can be assigned to something else, like a pointer. Note than when an array is passed to a function, the address of the array actually is passed as an actual pointer. The pointer is the function's parameter and that function parameter can be assigned to...

Upvotes: 2

user3629249
user3629249

Reputation: 16540

the posted code, when compiled with:

gcc -c -Wall -Wextra -Wconversion -pedantic -std=gnu11 

results in the following compiler messages:

gcc    -ggdb -Wall -Wextra -Wconversion -pedantic -std=gnu11 -c "untitled.c"  (in directory: /home/richard/Documents/forum)
untitled.c: In function ‘main’:
untitled.c:6:15: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
     int *ip = a;
               ^
untitled.c:7:26: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘long unsigned int’ [-Wformat=]
     printf("sizeof:\np: %d\n(*p+0): %d\n**p: %d\nip: %d\n*ip: %d\n",sizeof p, sizeof (*p+0), sizeof **p, sizeof ip, sizeof *ip);
                         ~^
                         %ld
untitled.c:7:38: warning: format ‘%d’ expects argument of type ‘int’, but argument 3 has type ‘long unsigned int’ [-Wformat=]
     printf("sizeof:\np: %d\n(*p+0): %d\n**p: %d\nip: %d\n*ip: %d\n",sizeof p, sizeof (*p+0), sizeof **p, sizeof ip, sizeof *ip);
                                     ~^
                                     %ld
untitled.c:7:47: warning: format ‘%d’ expects argument of type ‘int’, but argument 4 has type ‘long unsigned int’ [-Wformat=]
     printf("sizeof:\np: %d\n(*p+0): %d\n**p: %d\nip: %d\n*ip: %d\n",sizeof p, sizeof (*p+0), sizeof **p, sizeof ip, sizeof *ip);
                                              ~^
                                              %ld
untitled.c:7:55: warning: format ‘%d’ expects argument of type ‘int’, but argument 5 has type ‘long unsigned int’ [-Wformat=]
     printf("sizeof:\np: %d\n(*p+0): %d\n**p: %d\nip: %d\n*ip: %d\n",sizeof p, sizeof (*p+0), sizeof **p, sizeof ip, sizeof *ip);
                                                      ~^
                                                      %ld
untitled.c:7:64: warning: format ‘%d’ expects argument of type ‘int’, but argument 6 has type ‘long unsigned int’ [-Wformat=]
     printf("sizeof:\np: %d\n(*p+0): %d\n**p: %d\nip: %d\n*ip: %d\n",sizeof p, sizeof (*p+0), sizeof **p, sizeof ip, sizeof *ip);
                                                               ~^
                                                               %ld
untitled.c:9:17: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 2 has type ‘int (*)[3]’ [-Wformat=]
     printf("p: %x\tp+1: %x\n*p: %x\t*p+1: %x\n**p: %d\nip: %x\n*ip: %d",p,p+1,*p,*p+1,**p,ip,*ip);
                ~^
untitled.c:9:26: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 3 has type ‘int (*)[3]’ [-Wformat=]
     printf("p: %x\tp+1: %x\n*p: %x\t*p+1: %x\n**p: %d\nip: %x\n*ip: %d",p,p+1,*p,*p+1,**p,ip,*ip);
                         ~^                                                ~~~
untitled.c:9:34: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 4 has type ‘int *’ [-Wformat=]
     printf("p: %x\tp+1: %x\n*p: %x\t*p+1: %x\n**p: %d\nip: %x\n*ip: %d",p,p+1,*p,*p+1,**p,ip,*ip);
                                 ~^
                                 %ls
untitled.c:9:44: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 5 has type ‘int *’ [-Wformat=]
     printf("p: %x\tp+1: %x\n*p: %x\t*p+1: %x\n**p: %d\nip: %x\n*ip: %d",p,p+1,*p,*p+1,**p,ip,*ip);
                                           ~^                                     ~~~~
                                           %ls
untitled.c:9:61: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 7 has type ‘int *’ [-Wformat=]
     printf("p: %x\tp+1: %x\n*p: %x\t*p+1: %x\n**p: %d\nip: %x\n*ip: %d",p,p+1,*p,*p+1,**p,ip,*ip);
                                                            ~^
                                                            %ls
Compilation finished successfully.

The compiler finishes up by saying the compilation was successful. That does NOT mean that it is ok to run this code and expect valid results/output.

When you correct the code so it cleanly compiles, then please post a EDIT to your question that contains the modified/corrected code.

gcc    -ggdb -Wall -Wextra -Wconversion -pedantic -std=gnu11 -c "untitled.c"  (in directory: /home/richard/Documents/forum)
untitled.c: In function ‘main’:
untitled.c:6:15: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
     int *ip = a;
               ^
untitled.c:7:26: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘long unsigned int’ [-Wformat=]
     printf("sizeof:\np: %d\n(*p+0): %d\n**p: %d\nip: %d\n*ip: %d\n",sizeof p, sizeof (*p+0), sizeof **p, sizeof ip, sizeof *ip);
                         ~^
                         %ld
untitled.c:7:38: warning: format ‘%d’ expects argument of type ‘int’, but argument 3 has type ‘long unsigned int’ [-Wformat=]
     printf("sizeof:\np: %d\n(*p+0): %d\n**p: %d\nip: %d\n*ip: %d\n",sizeof p, sizeof (*p+0), sizeof **p, sizeof ip, sizeof *ip);
                                     ~^
                                     %ld
untitled.c:7:47: warning: format ‘%d’ expects argument of type ‘int’, but argument 4 has type ‘long unsigned int’ [-Wformat=]
     printf("sizeof:\np: %d\n(*p+0): %d\n**p: %d\nip: %d\n*ip: %d\n",sizeof p, sizeof (*p+0), sizeof **p, sizeof ip, sizeof *ip);
                                              ~^
                                              %ld
untitled.c:7:55: warning: format ‘%d’ expects argument of type ‘int’, but argument 5 has type ‘long unsigned int’ [-Wformat=]
     printf("sizeof:\np: %d\n(*p+0): %d\n**p: %d\nip: %d\n*ip: %d\n",sizeof p, sizeof (*p+0), sizeof **p, sizeof ip, sizeof *ip);
                                                      ~^
                                                      %ld
untitled.c:7:64: warning: format ‘%d’ expects argument of type ‘int’, but argument 6 has type ‘long unsigned int’ [-Wformat=]
     printf("sizeof:\np: %d\n(*p+0): %d\n**p: %d\nip: %d\n*ip: %d\n",sizeof p, sizeof (*p+0), sizeof **p, sizeof ip, sizeof *ip);
                                                               ~^
                                                               %ld
untitled.c:9:17: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 2 has type ‘int (*)[3]’ [-Wformat=]
     printf("p: %x\tp+1: %x\n*p: %x\t*p+1: %x\n**p: %d\nip: %x\n*ip: %d",p,p+1,*p,*p+1,**p,ip,*ip);
                ~^
untitled.c:9:26: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 3 has type ‘int (*)[3]’ [-Wformat=]
     printf("p: %x\tp+1: %x\n*p: %x\t*p+1: %x\n**p: %d\nip: %x\n*ip: %d",p,p+1,*p,*p+1,**p,ip,*ip);
                         ~^                                                ~~~
untitled.c:9:34: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 4 has type ‘int *’ [-Wformat=]
     printf("p: %x\tp+1: %x\n*p: %x\t*p+1: %x\n**p: %d\nip: %x\n*ip: %d",p,p+1,*p,*p+1,**p,ip,*ip);
                                 ~^
                                 %ls
untitled.c:9:44: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 5 has type ‘int *’ [-Wformat=]
     printf("p: %x\tp+1: %x\n*p: %x\t*p+1: %x\n**p: %d\nip: %x\n*ip: %d",p,p+1,*p,*p+1,**p,ip,*ip);
                                           ~^                                     ~~~~
                                           %ls
untitled.c:9:61: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 7 has type ‘int *’ [-Wformat=]
     printf("p: %x\tp+1: %x\n*p: %x\t*p+1: %x\n**p: %d\nip: %x\n*ip: %d",p,p+1,*p,*p+1,**p,ip,*ip);
                                                            ~^
                                                            %ls
Compilation finished successfully.

Upvotes: 1

P.W
P.W

Reputation: 26800

What you have here is constraint violation because you are using incompatible pointer types in the following initialization:

int *ip = a;

As per C11 standard section on Pointer declarators

For two pointer types to be compatible, both shall be identically qualified and both shall be pointers to compatible types.

and on Simple assignment/Constraints

the left operand has atomic, qualified, or unqualified pointer type, and (considering the type the left operand would have after lvalue conversion) both operands are pointers to qualified or unqualified versions of compatible types, and the type pointed to by the left has all the qualifiers of the type pointed to by the right;

The compiler is require to emit a diagnostic in this case which it does:

<source>:8:15: warning: initialization of 'int *' from incompatible pointer type 'int (*)[3]' [-Wincompatible-pointer-types]

     int *ip = a;

See Demo

When you compile a program, it is good practice to enable all warnings and treat warnings as errors so as to avoid (as far as possible) this kind of behavior.

Upvotes: 0

Related Questions