I'm trying to understand something in 2D-arrays.
int A[2][3] = {{20, 30, 40}, {50, 60, 70}};
printf("%p\n",A); // Output is 0x7ffde7e966d0
printf("%p\n",*A); // Output is 0x7ffde7e966d0
I understand that these two addresses have different scope and A 1
is completely different address than *A 1
, but my main misunderstanding is when using the derefrence operator it should produce a value not an address.
It looks like the name of the 2D-array is acting like a pointer that points to itself.
I tried this code
int *p = &p;
printf("%p\n",p); // Output is 0xfff1c9a94b0
printf("%p\n",*p); // Output is 0x1c9a94b0
the compiler gives me a warning
initialization of ‘int *’ from incompatible pointer type ‘int **’ [-Wincompatible-pointer-types]
but the code runs as above shown. If i tries to add more astrics int **p = &p; the compiler warning will be like ``int **’ from incompatible pointer type ‘int ***
and the strange thing is the output address is alaways the same for the frist 8 or 7 digits from right to left.
in this case can we call *p
is a pointer that points to it self ?
CodePudding user response:
If you want to produce a value, use the appropriate formatting string and type cast:
int A[2][3] = {{20, 30, 40}, {50, 60, 70}};
A[0][0]=1;
printf("%p\n",A); // Output is 0x7ffde7e966d0
printf("%p\n",*A); // Output is 0x7ffde7e966d0
printf("%d\n",*(int *)A); // Output is 1
In the case of:
int *p = &p;
you are just basically doing this:
int *p
p=&p;
which speaks for itself: it's the address of p in the stack
CodePudding user response:
Your printf
calls are somewhat incorrect: %p
expects a void *
, which neither A
nor *A
are, even after decaying to a pointer to their first element.
Consider this simple example:
#include <stdio.h>
int main() {
int A[2][3] = {{20, 30, 40}, {50, 60, 70}};
printf("&A=%p &A 1=%p sizeof(*&A)=%zu\n", (void*)(&A), (void*)(&A 1), sizeof(*&A));
printf(" A=%p A 1=%p sizeof( *A)=%zu\n", (void*)( A), (void*)( A 1), sizeof( *A));
printf("*A=%p *A 1=%p sizeof(**A)=%zu\n", (void*)(*A), (void*)(*A 1), sizeof(**A));
return 0;
}
On my system, the output is:
&A=0x7fff5b9877a0 &A 1=0x7fff5b9877b8 sizeof( A)=24
A=0x7fff5b9877a0 A 1=0x7fff5b9877ac sizeof( *A)=12
*A=0x7fff5b9877a0 *A 1=0x7fff5b9877a4 sizeof(**A)=4
The difference between the address produced for &A
and &A 1
is sizeof(*&A)
, which is the same as sizeof(A)
... and the same for the next 2 statements.
A
is an array of 2 arrays of 3 ints. In memory it is implemented as a sequence of 24 bytes, 4 for each of the 6 integers (on a system with 32-bit int
and 8-bit bytes, the most common values today). These 24 bytes are located at a specific address in memory determined by the definition location. The array A
, its first element A[0]
(is itself an array that can be referred to as *A
, or even 0[A]
) and A[0][0]
are all located at the same place, the address of the first byte of the first int
.
CodePudding user response:
Firstly you should know that pointers are just a variable, that instead of holding some number, or character, ... it holds the address of another variable. When you type int *p
that "*" indicates a pointer and that "int" indicates that the address that will be assigned to that pointer can only be the address of an integer type object. When you say int **p
it creates a pointer that can only hold an address of an integer pointer object(pointer to pointer). So it means that even pointers have their memory addresses.
"&" sign in an expression like this int *p = &p
means that pointer p will hold the memory address of pointer p
. This is invalid because pointer p
can only hold addresses of integers, not addresses of "integer pointers" - they are 2 separate things.
But there are void pointers(void *p
) that can hold the address of any type of object. I think this page will help you understand. And yes, you can make a pointer that points to itself void *p = &p
. This can be achievable because pointer p
in that case is not limited to a specific type.
CodePudding user response:
According to the C Standard (6.3.2.1 Lvalues, arrays, and function designators)
3 Except when it is the operand of the sizeof operator or the unary & operator, or is a string literal used to initialize an array, an expression that has type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points to the initial element of the array object and is not an lvalue. If the array object has register storage class, the behavior is undefined.
Consider the following demonstration program.
#include <stdio.h>
int main( void )
{
int a[] = { 1, 2, 3, 4, 5 };
printf( "sizeof( a ) = %zu\n", sizeof( a ) );
printf( "sizeof( a 0 ) = %zu\n", sizeof( a 0 ) );
}
Its output might look like
sizeof( a ) = 20
sizeof( a 0 ) = 8
In the expression a 0
the array designator a
is implicitly converted to pointer to its first element. That is the expression has the type int *
.
In your code snippet
int A[2][3] = {{20, 30, 40}, {50, 60, 70}};
printf("%p\n",A); // Output is 0x7ffde7e966d0
printf("%p\n",*A); // Output is 0x7ffde7e966d0
the expression *A
that is the same as A[0]
yields the first element of the array A
. It has the type int[3]
. But used as a function argument this one-dimensional array is implicitly converted to pointer of the type int * that points to its first element. In fact it is equivalent to the expression &A[0][0]
.
As for your question whether a pointer can be initialized by its address then a pointer of the type void *
can be initialized such a way.
Here is a demonstration program.
#include <stdio.h>
int main( void )
{
void *p = &p;
printf( "p = %p\n", p );
printf( "&p = %p\n", &p );
}
The program output is
p = 0x7fff3bef8dd8
&p = 0x7fff3bef8dd8
For a pointer of the type int *
you need to use casting like
int *p = ( int * )&p;
or
int *p = ( void * )&p;
CodePudding user response:
For the statements:
printf("%p\n",A); // Output is 0x7ffde7e966d0
printf("%p\n",*A); // Output is 0x7ffde7e966d0
The first thing to note is that this invokes undefined behavior because %p
specifier expects a void pointer:
printf("%p\n",(void*)A); // Output is 0x7ffde7e966d0
printf("%p\n",(void*)*A); // Output is 0x7ffde7e966d0
Secondly the above statements will result in the same address because the address of A
will be that of its first element which is A[0]
wich is really de the same as *(A 0)
wich is the same as *A
, which is also a pointer to the first element of the array A[0][0]
.
Essentially the addresses are the same, &A[0]
== &A[0][0]
== &A
.
For :
int *p = &p;
printf("%p\n",p); // Output is 0xfff1c9a94b0
printf("%p\n",*p); // Output is 0x1c9a94b0
The behavior of the above snippet is undefined and always be no matter the levels of indirection (asteriscs) you add to it, you will always have a type mismatch because you are assigning the address of a variable of the same type (unless you cast it). The explanation for the value you are getting, in this particular case, could maybe be attributed to the difference in size between int
which is usually 4 bytes and int*
which is usually 8 bytes, but again undefined behavior is undefined, and there is no accurate diagnose for it, the result can be anything.