Pointer to array of elements when dereferenced return an address.
Since it is holding the address of the first element of the array, dereferencing it should return a value.
int arr[] = { 3, 5, 6, 7, 9 };
int *p = arr;
int (*ptr)[5] = &arr;
printf("p = %p, ptr = %p\n", p, ptr);
printf("*p = %d, *ptr = %p\n", *p, *ptr);
Output:
p = 0x7fff6ea72d10, ptr = 0x7fff6ea72d10
*p = 3, *ptr = 0x7fff6ea72d10
Why does *ptr return the base address of the array, shouldn't it return the value at that address??
Why does *ptr return the base address of the array, shouldn't it
return the value at that address??
(p3) Except when it is the operand of the sizeof operator, the _Alignof 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. C11 Standard - 6.3.2.1 Other Operands - Lvalues, arrays, and function designators(p3)
int (*ptr)[5] = &arr;
ptr is a pointer-to-array of int [5]. When you dereference ptr you get array of int[5]. How is an array of int[5] accessed?
Rule 6.3.2.1 provides the answer:
"array of type" is converted to an expression with type "pointer to type" that points to the initial element of the array object...
Now if you dereference again (e.g. **ptr), then you get the value of the 1st element.
The question was
"Why does *ptr return the base address of the array, shouldn't it return the value at that address?"
It does return the value at that address, which is the array arr.
Think about a queue of people: you can point to the first person and say "that person over there" or you can point to the same person and say "that queue over there". There are 2 things at the same location: a person and a queue. Same thing happens with arrays: person * for that "person over there" and person (*)[42] "for that queue of 42 people". If you dereference a pointer to queue, you get a queue. If you take the first from the queue you get a person.
But then the array itself will decay to address to the first element when it is given as an argument to printf. Thus here,
int arr[] = { 3, 5, 6, 7, 9 };
int (*ptr)[5] = &arr;
// undefined behaviour really, all pointers should be cast to void *
printf("%p %p %p %p", *ptr, &ptr[0], arr, &arr[0]);
all these 4 expressions will result in pointer to int, and the value is the address of the first element in the array (the address of 3 in arr).
Here is a simple, less technical explanation.
How are you setting p? = arr;
How are you setting ptr? = &arr;
Your question really has nothing to do with arrays at all. arr could be literally any type and the answer would be the same: & gets the address of arr, so whatever arr is, ptr is storing its address while p is storing arr itself.
If you do *ptr, you will dereference that address and thus get a value equal to p.
int arr = 3;
// clearly these are different!
int p = arr;
int* ptr = &arr;
Similarly
int x = 3;
int* arr = &x;
// clearly these are different!
int* p = arr;
int** ptr = &arr;
// so of course they dereference differently
printf("*p = %d, *ptr = %p\n", *p, *ptr);
The behavior you see is a result of 'c' interpreting arr as a pointer to the memory location of the first element. Pointer to the array &arr will be an address of the array itself in memory, which is also the address of its first element. As a result arr and &arr yield the same values. Try this:
printf("array = %p, &array = %p\n", arr, &arr);
Thought the values are the same, types are different. arr is a variable, whether &arr is a pointer to the variable.
ptr reflects the same picture. Its value ptr = &arr makes it a pointer to an array. It contains the address of the array. *ptr returns the array itself, which in 'c' interpretation is the address of the first element of the array. As a result values for ptr and *ptr are the same as for &arr and arr.
Hope it makes it clearer (not murkier) :-)
Arrays are pointers. Arrays are not pointers, see the comments below
A pointer to an array is a pointer, pointing at a pointer. Try de-referencing twice over, that should yeild a value.
Related
This question already has answers here:
Why can't I increment an array?
(5 answers)
Is an array name a pointer?
(8 answers)
Closed 1 year ago.
I have an array arr say
int arr[3] = {1, 2, 3};
so as per my knowledge this arr is just like any variable that has a name arr just like
int a = 4;
a is an integer variable that asks 4 bytes of memory. And arr asks 3 * 4
= 12 bytes of memory and arr has properties like 12 bytes of memory and when used as an Rvalue it decays to a
(pointer value not a pointer variable)
so as it decays to a pointer value like &arr[0] we can use a pointer variable to point (grab the address)
int* ptr = arr; //here arr implicitly converts to &arr[0]
so here arr and ptr have the same address but ptr is like copied the memory of &arr[0] and stores it. Whereas arr is literally the address in the memory which only decays like &arr[0] when used as Rvalue.
if we do something like
arr++;
complier throws error as Expression must be a modifiable lvalue
As the arr is allocated on the stack we cannot change the address
because we are asking cpu to change the address of the array, if we change it we loose the array address and cannot further access it
Code
#include <stdio.h>
int main()
{
int arr[3] = { 1, 2, 3 };
arr++; // not allowed
int* p = arr;
p++; // allowed because its a copy of (arr) address.
return 0;
}
That's how what i know and correct me with more resources.
arr is not a pointer, it's an array. When you use the word arr the compiler may convert it to a pointer for you - it does &arr[0] automatically, and gets the address of the first element, which is a pointer value, not a pointer variable. And you can't change values. You can't do (&some_variable)++;, you can't do 5++;, and you can't do (&arr[0])++; which is what arr++; would mean.
Arrays are not pointers.
Consider the following demonstrative program.
#include <stdio.h>
int main(void)
{
int arr[3] = { 1, 2, 3 };
int *p = arr;
printf( "sizeof( arr ) = %zu\n", sizeof( arr ) );
printf( "sizeof( p ) = %zu\n", sizeof( p ) );
return 0;
}
Its output might look like
sizeof( arr ) = 12
sizeof( p ) = 8
Arrays are non-modifiable lvalues. That means that you for example can not assign one array to another or apply an increment operator.
On the other hand, arrays used in expressions are implicitly converted (with rare exceptions) to pointers to their first elements.
From 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.
So for example in this declaration
int *p = arr;
the array arr used as an initializer expression is implicitly converted to pointer to its first element that has the type int *.
To set the pointer p to point to the second element of the array arr you could use the pointer arithmetic the following way
int *p = arr + 1;
According to my knowledge
**ptr = the address of memory location of the pointer variable ptr
&ptr = the address of memory location where the value of ptr is stored.
Am I correct or **ptr == &ptr?
If they are equal whether I can pass &ptr as a pass by address for a function as a replacement to ptr? Knowledge me on this.
It might help if you understand that for any pointer (or array) p and index i the expression *(p + i) is equivalent to p[i].
Now if i is zero that means we have *(p + 0) which is equal to *p, and its equivalent expression p[0]. That means when you do dereference a pointer you get the value of where it points.
Double-dereferencing a pointer only works if the pointer is pointing to another pointer.
You understanding of the address-of operator & is correct though.
Lets work on an example:
int a = 10;
int *p = &a; // Makes p point to the variable a
int **pp = &p; // Makes pp point to the variable p
Now if we do *pp we get the pointer p, and if we to **pp we get the variable a and its value.
printf("Value of a is %d\n", a); // Will print "Value of a is 10\n"
printf("Value of *p is %d\n", *p); // Will print "Value of *p is 10\n"
printf("Value of **pp is %d\n", **pp); // Will print "Value of **pp is 10\n"
Also, using pointer to pointer might seem not very usable, but if you think about dynamically allocated arrays things change. For a dynamically allocated array you need to use a pointer, and if you want a matrix (i.e. an array of arrays) you need to use pointer to pointer, if you want to allocate both "dimensions" dynamically.
Furthermore, while C doesn't support passing arguments by reference, it can be emulated using pointers, and if you need to pass a pointer by reference you do it by passing a pointer to a pointer (using the address-of operator).
Lastly a small fun fact. I started this answer by telling you that *(p + i) and p[i] are equivalent. Because of the commutative property of addition, the expression *(p + i) is equivalent to *(i + p) which means that p[i] is equivalent to i[p]. Don't do it in real code though, it will only obfuscate the code and cause confusion for new readers of the code.
Pay attention to the context: There is a difference when declaring and when using the pointer. In general, & is taking the address and ** is dereferencing the pointer twice. Obviously, these are not the same.
But in variable decfinitions, ** declares a pointer to a pointer. The declared variable can the take the address of a pointer as value:
int d = 10;
int *p = &d;
int **pp = &p;
This still doesn't mean that **p and & are the same: Here, the ** is part of the variable's type: pointer to pointer to int.
The same applies to function argumets: The function
void f(int **p);
takes a pointer to pointer to int as argument and you can pass it the address of a pointer to int.
'*' operator is used to hold a memory address.
'&' operator returns the address at which the variable is held.
for example
int a = 10; (10 is located in memory at, for example, 0xddffff0
int *b = &a; (&a is the same thing as 0xddffff0, so b now points to that address)
So '&' operator returns the address while '*' operator point at the address.
Actually my knowledge on double pointer was wrong .
**ptr - Value of the variable pointed by another pointer or we can say it is a pointer to a pointer
let me clarify with an ex
#include<stdio.h>
int main()
{
int num = 100 , *p , **ptr2ptr ;//Address of num=2000 ,p=3000 ,ptr2ptr=4000
p = #
ptr2ptr = &p;
printf("Single pointer *p =%d\n",*p);
printf("Double pointer **ptr2ptr=%d \n", **ptr2ptr);
printf("Address stored in p variable =%d \n", p);
printf("Address of p variable=%d\n", &p);
printf("Address of ptr2ptr=%d", &ptr2ptr);
return(0);
}
Output
Single pointer *p = 100
Double pointer **ptr2ptr= 100
Address stored in p variable =2000
Address of p variable=3000
Address of ptr2ptr=4000
From the above example it is clear **ptr2ptr(100) not equal to &ptr2ptr(4000) .
So I have found answer for my question .
Can anyone explain how these values will be printed and why p and *p are returning the same values.
#include <stdio.h>
int main(){
int arr[] = {1,2,3,4};
int (*p)[4];
p = &arr;
printf("%u %u %u %u %u", arr, &p, p, *p, **p);
p++;
printf("\n%u %u %u %u %u", arr, &p, p, *p, **p);
return 0;
}
outputs on my machine are as follows:
2686768 2686764 2686768 2686768 1
2686768 2686764 2686784 2686784 2686792
Your example is messy, but pointer arithmetic is messy in general, disrespectful to types. Your example does not make sense from a type theory point of view.
arr points to the first element of the array. Note that arr[i] is equivalent to *(arr+i). arr is a 4-elements array of type int.
p is a pointer to a 4-element array of type int.
You assign to p the address of &arr, which has the same address as arr (but the type is different, see below).
Then you print it out and this means:
arr is the address of the first element of the array
&p is the address of p
p is the address of &arr (whole array), which is the address of arr, which is the address of the first element in the array
*p is the address of arr, which is the address of the first element in the array
**p is trying to dereference *p, which is dereferencing arr, which actually is the first element of the array
After you increment p++: arr and &p don't change, the rest does
From the C Book
We have already emphasized that in most cases, the name of an array is
converted into the address of its first element; one notable exception
being when it is the operand of sizeof, which is essential if the
stuff to do with malloc is to work. Another case is when an array name
is the operand of the & address-of operator. Here, it is converted
into the address of the whole array. What's the difference? Even if
you think that addresses would be in some way ‘the same’, the critical
difference is that they have different types. For an array of n
elements of type T, then the address of the first element has type
‘pointer to T’; the address of the whole array has type ‘pointer to
array of n elements of type T’; clearly very different. Here's an
example of it:
int ar[10];
int *ip;
int (*ar10i)[10]; /* pointer to array of 10 ints */
ip = ar; /* address of first element */
ip = &ar[0]; /* address of first element */
ar10i = &ar; /* address of whole array */
printf("%u %u %u %u %u", arr, &p, p, *p, **p);
arr is the array itself. When the array name is used in an expression like this, it decays to a pointer to the first element, so you get the address of that element.
&p is the address where the array pointer is stored. The only reason why you see this as the same address as the others is because you are running optimized code. Disable optimizations or declare p as static volatile and you'll see a change.
p is the address of the array, which will of course be the same as the address of the first element.
*p gives you an array type, which then decays into a pointer to the first element. This is identical to arr.
**p gives you the contents of the first element in the array.
p++ will increase the pointer by the rules of pointer arithmetic. Thus the address that p points at will be increased by the size of what it points at, which is an array of 4 ints, each 4 bytes large (assuming 32 bit). Therefore p will now point outside valid memory and anything will happen if you try to access it.
Let us take an example :--
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
int *p = NULL;
For the variable arr, will there be any memory allocation ??
Now, what will happen if =>
p = arr;
p = &arr;
p = &arr[0];
Please help me out to understand this.
This declaration:
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
causes 10 * sizeof (int) bytes to be allocated to hold the 10-element array object. (No space for any pointer object is allocated.) The array is initialized as specified.
int *p = NULL;
creates a single pointer object and initializes it to contain a null pointer value.
p = arr;
arr is an expression of array type. In most contexts, its value is implicitly converted to a pointer to its first element. So this assignment causes p to point to the first (0th) element of arr; *p == 1.
p = &arr;
This is invalid. &arr is of type int(*)[10], or pointer to array of 10 ints. p is of type int*. The types are incompatible. Any conforming C compiler must diagnose this error. (The diagnostic may be a non-fatal warning, but don't let that fool you; it's still an error, what the C standard calls a "constraint violation".)
p = &arr[0];
This is identical to p = arr;. arr[0] is the first (0th) element of the array, an int object with the value 1. &arr[0] is the address of that int object, and is of type char*. So this also causes p to point to the initial element of the array arr.
After this assignment, you can use either arr or p as the prefix for an indexing operator. The indexing operator is actually defined to take a pointer, not an array, as its prefix, so arr[0] uses the result of the array-to-pointer conversion, making it identical to p[0].
But arr and p still cannot always be used interchangeably. For example, sizeof arr gives you the size of the array object (10 * sizeof (int)), while sizeof p gives you the size of a pointer (sizeof (int*)).
Suggested reading: Section 6 of the comp.lang.c FAQ.
(To answer the question in your title, the compiler doesn't, or at least isn't required to, allocate memory at run time for the name of an array. It won't allocate 3 bytes of memory at run time because you named your array arr, or 22 bytes because you called it array_with_a_long_name. It might do so for debugging purposes, but then any such allocated space isn't accessible to your program.)
arr[10] creates locations for 10 ints.
p = arr ;
p= &arr[0] ;
are the same thing.
&arr is not something generally useful. It is a int (*)[10] which the compiler should complain about assigning to p.
In fact, if you do a little test and print out the addresses of these three:
printf("X: %lx %lx %lx\n", (long) arr, (long) &arr, (long) &arr[0]) ;
gcc ends up giving you the same thing for all three cases.
% ./a.out
X: 7fff906b5b20 7fff906b5b20 7fff906b5b20
But where you can really see the difference is if you ask for each item +1 :
printf("X: %lx %lx %lx\n", (long) arr, (long) &arr, (long) &arr[0]) ;
printf("X+1: %lx %lx %lx\n", (long) (arr +1), (long) ( &arr +1) , (long) ( &arr[0] +1 )) ;
% ./a.out
X: 7fff73c105b0 7fff73c105b0 7fff73c105b0
X+1: 7fff73c105b4 7fff73c105d8 7fff73c105b4
arr +1 is four bytes larger than arr (the size of an int), as is &arr[0] +1, but &arr +1 is forty bytes larger, the size of the entire array.
Storage is not set aside for variable names (arrays or otherwise), except to support debuggers.
Except when it is the operand of the sizeof or unary & operators, or is a string literal being used to initialize an array in a declaration, an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T", and the value of this expression will be the address of the first element of the array.
So, taking your three cases:
p = arr;
The expression arr has type "10-element array of int". Since it is not the operand of either the sizeof or unary & operators, it is converted to an expression of type "pointer to int", or int *, and its value is the address of the first element of the array.
p = &arr;
The expression arr has type "10-element array of int". Since arr is the operand of the unary & operator, the conversion above is not performed; instead, the type of the expression &arr is "pointer to 10-element array of arr", or int (*)[10]. The value is the same as the above expression (the address of the array is the same as the address of the first element of the array), but the types of the two expressions are different (int * vs. int (*)[10]), and types matter for things like pointer arithmetic.
p = &arr[0];
Gives the same type and result as p = arr;.
For your array, storage is set aside as follows:
+----+
arr[0]: | |
+----+
arr[1]: | |
+----+
... ...
+----+
arr[9]: | |
+----+
Note that there is no separate storage for a variable named arr that points to the beginning of the array; that pointer value is inferred from the array expression as described above. You can assign to arr[N], but there's no separate arr to assign anything to (part of the reason why array expressions are non-modifiable lvalues).
I ran into a pointer dereferencing problem.
In C, &a means the address of a. If a is a pointer ,then &a simply means the address of that pointer.
So if we have:
char ptr [] = "abcd"
ptr should be a pointer pointing to the first character, which is 'a'. therefore,
&ptr
should be the address of ptr, which is different than the address of 'a'. However, when I tried the following code I got really confused:
int main()
{
char a [] = "abcd";
printf("0x%X 0x%X", a, &a);
}
Output: 0xBF7E62AB 0xBF7E62AB
Can someone explain why a and &a have the same value? Based on my understanding they should be different. thanks in advance
So if we have: char ptr [] = "abcd", ptr should be a pointer pointing to the first character.
No. Not at all.
ptr is an array. And an array is not a pointer.
Indeed, if you declared ptr as a real pointer, then you would get the expected behavior:
const char *ptr = "abcd";
printf("ptr = %p, &ptr = %p\n", (void *)ptr, (void *)&ptr);
As to why the address of the array is the same as the address of its first element: it's quite logical. The array represents a contiguous sequence of elements. The address of the array is where the array begins in memory. It begins where its first element begins. So, the address of the first element is (rather "can be" -- the standard does not mandate this behavior) the same as the address of the array itself.
+-----------+-----------+- - - -
| element 1 | element 2 |
+-----------+-----------+- - - -
^ start of array
^ start of first element
Can someone explain why a and &a have the same value? Based on my understanding they should be different.
In the statement
printf("0x%X 0x%X", a, &a);
Both a and &a are of different types. a is of char * type (after decay) while &a is of char (*)[5] type.
a decays to a pointer to the first element, therefore a is the address of first element of the string. While &a is the address of the string "abcd" and it is equal to the address of first element.
An array is not a pointer. That's right when you said &p is the address of the pointer, if p is definied like this:
char *p;
An array is different and don't has exactly the same behavior.
With the arrays:
char a[] = "abc";, &a[0] is the address of the first element in your array, which is the same as a.
char a[] = "abcd" does not declare a pointer a to "abcd" but an array. Even if an array can decay to a pointer, it is a different type for which &a and a yield the same address.
Basically a yields the address to the first element of the array, so it is equivalent to &a (and to &a[0]).
Arrays will always reference the location where it is stored in memory, that's why when you print a, it gives you the address where it is, which is equal to getting the pointer pointing at the array (&a)
To get the behaveour you seek change
char a [] = "abcd";
to
char *a = strdup("abcd");
or for a readonly string
const char *a = "abcd";
You will then get a different address for a and &a.
When passing an array to a function, the array gets converted to a pointer.
With your original program try
printf("%d %d\n",sizeof(a),sizof(&a));
The first will vary with the size of the string, the second will be based on the pointer size on your machine.