I don't understand why when dereferencing a pointer to an array, the result is the address of the first value of the array
int array[2][2] = {{0,1},{0,1}};
int (*p)[2];
p = array;
p = address of a[0][0], p+1 = address of a[1][0],
*p = address of a[0][0], (*p)+1 = the address of a[0][1];
I understand that p is a pointer to an array of 2 integers, not a pointer to an integer. But if we print out the value of p, it's still the address of an integer. I want to know what's going on under the hood? Is p a pointer to an array of pointers? So we have to dereference it twice to get the value of the integer its pointing?
A pointer to an int,
int* p;
is a variable, stored in a location, that contains the address of another variable (int).
When we dereference it, we get the value of that variable. How does this process work exactly with a pointer to an array?
The address of an array is the same as the address of its first element.
Given the definition int array[2][2] = {{0,1},{0,1}};, the compiler arranges some location in memory to contain the int values 0, 1, 0, and 1. Let’s say that location has address 1000, and the int value 0 is stored in bytes 1000-1003, 1 is stored in 1004 to 1007, 0 is stored in 1008 to 1011, and 1 is stored in 1012 to 1015.
Where does the element array[0][0] start in memory? At location 1000.
Where does the array array start in memory? At location 1000.
Where does the array array[0] start in memory? At location 1000.
The array starts in memory at the same location its first element starts in memory. Also, array[0], which is itself an array, starts at the location 1000.
So, after p = array;, p points the location 1000. And the element array[0][0] also starts at location 1000. So, when you print p, as with printf("%p\n", (void *) p);, it is unsurprising you get the same result as when you print the address of array[0][0], as with printf("%p\n", (void *) &array[0][0]);.
An array is automatically converted to the address of its first element.
Next, let’s consider *p. The type of p is int (*)[2], a pointer to an array of 2 int. Therefore, *p is an array of 2 int.
In particular, *p is an array. Suppose we attempt to print it by passing it as an argument to printf. What happens?
In C, when an array is used in an expression, it is automatically converted to the address of its first element (except when the array is the operand of sizeof or unary & or is a string literal used to initialize an array). So, if you use *p as an argument to printf, it initially means array[0], but that array is converted to the address of its first argument. So passing *p as an argument actually passes &array[0][0] (or, equivalently &(*p)[0]).
Thus, printf("%p\n", (void *) *p); will print the same address as printf("%p\n", (void *) &a[0][0]);.
Value at an array can be accessed using
array[i] = *(array+i) (expansion of [i]).
Similarily, (*p)[i] = *(*(p+i)). So, we need to dereference twice to access the value.
If you want to access, array[0][0], you have to use *(*(p+0)+0) = **p;,
Similarily, array[0][1] can be accessed using *(*(p+0)+1) = *((*p)+1);
Note, *p points to first row (stores address of array[0][0]), and *(p+1) points to second row (stores address of array[1][0]).
Please check the below code :
#include <stdio.h>
int main()
{
int array[2][2] = {{1, 2}, {3, 4}};
int(*p)[2];
p = array;
printf("The address of array[0][0] is %p \n",&array[0][0]);
printf("The address of *p is %p \n",*p);
printf("The address of array[1][0] is %p \n",&array[1][0]);
printf("The address of *(p+1) is %p \n",*(p+1));
printf("The value of array[0][0] is %d \n",array[0][0]);
printf("The value of **p is %d \n",**p);
printf("The value of array[0][1] is %d \n",array[0][1]);
printf("The value of *((*p)+1) is %d \n",*((*p)+1));
return 0;
}
The output is:
The address of array[0][0] is 0x7fff6e8781a0
The address of *p is 0x7fff6e8781a0
The address of array[1][0] is 0x7fff6e8781a8
The address of *(p+1) is 0x7fff6e8781a8
The value of array[0][0] is 1
The value of **p is 1
The value of array[0][1] is 2
The value of *((*p)+1) is 2
Related
#include <stdio.h>
int main()
{
int arr[5];
arr[0] = 10;
arr[1] = 20;
arr[2] = 30;
arr[3] = 40;
arr[4] = 50;
int *p = &arr;
printf("Memory address of first index: %p\n", &arr[0]);
printf("Memory address of pointer: %p\n", &p);
return 0;
}
OUTPUT
Memory address of first index: 000000000061FE00
Memory address of pointer: 000000000061FDF8
They are are not the same. Is my machine bad?
First of all the compiler should issue a message relative to this declaration
int *p = &arr;
The problem is that the right hand side expression has the type int( * )[5] while the initialized object has the type int * and there is no implicit conversion between these two pointer types.
You should write either
int *p = arr;
In this case the array designator is implicitly converted to a pointer to its first element. Or
int ( *p )[5] = &arr;
The pointer p occupies its own extent of memory. So its address is different from the address of the extent of the memory occupied by the array arr.
On the other hand, if you will output the value stored in the pointer p like for example
printf("Memory address stored in the pointer p: %p\n", ( void * )p);
then it will be equal to the address of the first element of the array arr
printf("Memory address of first index: %p\n", ( void )&arr[0]);
arr is an array. It and its elements start at some place in memory.
p is a pointer to the array. Its value is an address. That address needs to be stored somewhere else in memory. That place is different from where the array is stored.
printf("%p\n", (void *) p); prints the value of p, which will be the address of arr (and of &arr[0], since the first element is at the start of the array).
printf("%p\n", (void *) &p) prints the address of p, which is where p is.
If you try that piece of code
#include<stdio.h> int main() {
// Pointer to an integer
int *p;
// Pointer to an array of 5 integers
int (*ptr)[5];
int arr[] = { 3, 5, 6, 7, 9 };
// Points to 0th element of the arr.
// Points to the whole array arr.
ptr = &arr;
printf("p = %p, address of P = %p\n", p, &p);
return 0; }
You will get something like p = 0x7fff8e9b4370, P address = 0x7fff8e9b4340
which means the address of pointer P is something and the data inside it is another
but if you try the same with the pointer of the array like this
#include<stdio.h> int main() {
// Pointer to an integer
int *p;
// Pointer to an array of 5 integers
int (*ptr)[5];
int arr[] = { 3, 5, 6, 7, 9 };
// Points to 0th element of the arr.
p = arr;
// Points to the whole array arr.
ptr = &arr;
printf("arr = %p, arr address = %p\n", arr, &arr);
return 0; }
You will get something like arr = 0x7ffda0a04310, arr address = 0x7ffda0a04310
So how come that a pointer data is the same the pointer Address in memory ?!! when we dereference the address of the arr pointer we should get the number 3 but as i understand from this is the address location 0x7ffda0a04310 in the memory has 0x7ffda0a04310 as a data
so where i am mistaken ?
printing p means print p's value, while p's value is address of a integer number or address of an integer array.
printing &p means you print location of p on memory.
printing arr will show address of first element of the array, it is &arr[0].
printing &arr will show location of arr on memory, it is also adress of first element of the array
So printing p will be different with printing &p.
arr and &arr are different types but it will give you the same result.
This is because when you use the symbol of an array, it actually evaluates to &arr (address to first element). So because of this arr and &arr are the same address (but not the same type!).
arr is of type int*
&arr is of type int(*)[5]
The difference is when you do pointer arithmetics. Incrementing arr will go to the address of the next element. So *(arr+1) is essentially the same as arr[1].
Incrementing &arr jumps over the whole array (incrementing a pointer always jumps the whole size of the type)
What you've discovered is that the address of an array is the same as the address of its first member.
When you use the array arr in an expression, in most cases it decays to a pointer to its first element. So arr in an expression is equivalent to &arr[0]. Since the members of arr have type int, the expression &arr[0] (and by extension arr) have type int *.
In some cases however this decay does not happen. One of those is when an array is the operand of the & operator. So the expression &arr has type int (*)[5], i.e. a pointer to a array of int of size 5.
As for why the values of these two address are the same, it makes sense if you look at it:
arr
-------
0x7ffda0a04310 | 0 |
-------
| 0 |
-------
| 0 |
-------
| 0 |
-------
0x7ffda0a04314 | 1 |
-------
| 1 |
-------
| 1 |
-------
| 1 |
-------
...
Looking at this, you can see that the array itself and the array's first element start at the same address.
So arr (as an expression) has type int * while &arr has type int(*)[5], but both have the same value.
I have a 2D array (int s[4][2])and I created a pointer as int (*p)[2].
The pointer p is now assigned the address of 1st element of row within a for loop.
for (int i = 0; i<4; i++)
p = &s[i];
Now when I try to write the array elements data using dereferencing, I get wrong values.
printf ("%d \n", *p)
However, if I create another pointer and link that with the previous pointer
int *ptr = p;
and dereference pointer ptr I get correct values.
printf ("%d \n", *ptr)
When both the pointers are pointing to the same address why does one pointer (*ptr) work as expected and other (*p) does not return expected values?
If p is a pointer to array then *p is array of 2 ints (int[2]). So, you can't print an array element like this:
printf ("%d \n", *p);
To print the array elements through the pointer p, you need to do:
printf ("%d \n", (*p)[0]); /* first element */
printf ("%d \n", (*p)[1]); /* second element */
p is not a pointer to an int. It is a pointer to an array of two int. Therefore *p is also an array of two int. Since it is not an int, printing it using %d gives undefined behaviour.
You would not be able to "link" ptr to p because of a type mismatch (ptr is a pointer to int, and p (as already noted) is a pointer to an array of two int. Hence the assignment ptr = p would not compile. If you are forcing it to compile (e.g. ptr = (int *)p), then ptr and p will have the same value (i.e. they will identify the same location in memory) but different type (i.e. dereferencing them interprets the contents of that memory differently).
The value (ignoring type) of p will be the address of s[0][0]. Similarly, the value of ptr will be the address of s[0][0].
As a result printf("%d\n", *ptr) will print the value of s[0][0].
When both the pointers are pointing to the same address why does one pointer (*ptr) work as expected and other (*p) does not return expected values?
*p evaluates to an int[2], an array.
Passing an int[2], an array to a function, results in passing a pointer the array's 1st element, a int*.
*ptr evaluates to an int.
Passing an int to a function, results in passing an int to a function ... :-)
By
int (*ptr)[2] ; // means int[2]<-(*ptr)
You got pointer to an array of two integers
The pointer p is now assigned the address of 1st element of row
within a for loop.
This is not correct, technically p is assigned the address of the entire int[2] block (Hint : use sizeof to verify the size).
What is the problem with printf ("%d \n", *ptr)
*ptr by itself doesn't contain a integer but it holds the address of the first element of int[2] ie *ptr itself is a pointer.
A working example would be
int main(void)
{
int i;
int s[4][2]={{0,1},{2,3},{4,5},{6,7}};
int (*ptr)[2];
for(i=0;i<4;i++)
{
ptr=&s[i];
printf("i:%d\n",i);
printf("Element 1 : %d\n",(*ptr)[0]);
printf("Element 2 : %d\n",(*ptr)[1]);
/* Replacing (*ptr)[1] with *((*ptr)+1) gives you the same
* results
*/
}
return 0;
}
Output
i:0
Element 1 : 0
Element 2 : 1
i:1
Element 1 : 2
Element 2 : 3
i:2
Element 1 : 4
Element 2 : 5
i:3
Element 1 : 6
Element 2 : 7
I've just read in the book "The C Programming Language" that array is not a variable and saw that assignment of array to pointers (and vice versa) can't be done as a result. So if array is not a variable then what is it?
int numbers[] = {1,2,3}
numbers is not a variable, it is the array name which is nothing but the address of the first element in the array. To verifiy this, look at the address of numbers and the address of numbers[0] by doing this: printf("%p and %p and %p", &numbers, numbers, &numbers[0]); All the the three pointers will have the same values since numbers is nothing but the address of the first element in the array. Therefore numbers is not a variable that contain a pointer or a value since it does not have a dedicated address in the memory to store value in it.
However, look at this pointer variable:
int *pnumbers = numbers;
`printf("%p and %p and %p", &pnumbers, pnumbers, &pnumbers[0]);`
You will notice that &pnumbers has a different address in memory, and that's because pnumber has a dedicated address in the memory where it stores the address of the first element in the array numbers.
Putting the code all together:
#include <stdio.h>
main(){
int numbers[] = {1,2,3};
printf("%p and %p and %p\n", &numbers, numbers, &numbers[0]); // Address of numbers, value of numbers, first element of numbers
int *pnumbers = numbers;
printf("%p and %p and %p\n", &pnumbers, pnumbers, &pnumbers[0]); // Address of pnumbers, value of pnumbers, first element of the array pnumbers is pointing to
}
Output
0xbfb99fe4 and 0xbfb99fe4 and 0xbfb99fe4 // All three have the same address which is the address of the first element in the array
0xbfb99fe0 and 0xbfb99fe4 and 0xbfb99fe4 // The first one is different since pnumbers has been allocated a memory address to store a pointer which is the first element of the array numbers
Array is a data structure containing a number of values, all of which have the same type and array names are non-modifiable l-values(named memory locations)-- it is addressable, but not modifiable. It means that it can't be modified or can't be the left operand of an assignment operator.
int a[10] = {0};
int *p = a; //OK
a++ // Wrong
a = p; // Wrong
It's a placeholder. A symbol to represent a commonly used method of referring to a sequential section of memory. It's not a variable all by itself.
int main(int argc, char** argv)
{
int array[10];
int value'
int* pointer;
value = array[0]; // Just fine, value and array[0] are variables
array[0] = value; // Just fine, value and array[0] are variables
pointer = &array[0]; // Just fine, &array[0] is an address
pointer = array; // Also just fine
//Because the compiler treats "array" all by itself as the address of array[0]
//That is: array == &array[0]
&array[0] = pointer // ERROR, you can't assign the address of something to something else.
array = pointer; // ERROR, array is not a variable, and cannot be assigned a value.
//Also bad, but technically they compile and could theoretically have their use
pointer = value;
pointer = array[0];
array[0] = pointer;
//Intermixing pointers and non-pointer variables is generally a bad idea.
}
array is often treated like a variable because it represents the adddress of (the first item in) that block of memory. But it's not a variable. It doesn't have it's own memory to store anything. People set pointers equal to 'array' because it's a handy convention, compilers know what that means, and it's pretty common.
array is a sequence of elements of the same type. if you assign a pointer to an array, pointer will point to the address of first variable from an array.
int a[10];
int *p;
int *p2;
p = a;
p2 = &a[0];
printf("%d\n", p == p2);
output:
1
I've just read in the book "The C Programming Language" that array is not a
variable and saw that assignment of array to pointers (and vice versa)
Vice versa is allowed... An array is like a constant pointer (you cant change the address it is pointing to). However, you can assign that address to a pointer.
#include <stdio.h>
int main()
{
int x[3] = {1, 2, 3};
int *p = x;
p[0] = 50;
printf("%d", x[0]);
}
char arr[10]="hello";
I guess &arr in this array is of type char(*)[10].
If I am right, what is the type of *(&arr)? Is it of type base address or address to first element in array?
Given:
char arr[10];
as you say, &arr is of type char (*)[10]. Of itself, *(&arr) is of type char [10], but in most contexts (other than sizeof()) it will become char * when it is used.
Sample code:
#include <stdio.h>
int main(void)
{
char arr[10] = "hello";
printf("arr[10] = \"%s\"\n", arr);
printf("arr = %p\n", arr);
printf("&arr = %p\n", &arr);
printf("*(&arr) = %p\n", *(&arr));
printf("sizeof(*(&arr)) = %zu\n", sizeof(*(&arr)));
printf("arr+1 = %p\n", arr+1);
printf("&arr+1 = %p\n", &arr+1);
printf("*(&arr) = \"%s\"\n", *(&arr));
return 0;
}
Sample output (GCC 4.7.1, Mac OS X 10.8.3):
arr[10] = "hello"
arr = 0x7fff4ff15500
&arr = 0x7fff4ff15500
*(&arr) = 0x7fff4ff15500
sizeof(*(&arr)) = 10
arr+1 = 0x7fff4ff15501
&arr+1 = 0x7fff4ff1550a
*(&arr) = "hello"
Note that although the values of arr and &arr are the same, the types are different. This is most clearly demonstrated by the arr+1 and &arr+1 lines. As you can see, incrementing &arr by one adds the sizeof of the object it points at (a char [10]) to the address.
You can extend the example to add other values as you see fit.
The expression *(&arr) is the same type as arr. The dereference and address-of operators cancel out each other out.
You use the address-of operator & to get the address, i.e. get a pointer. You use the dereference operator * to get the value of what a pointer points to. So using both of them like that doesn't make any sense in that context.
*(&arr) is of type base address, where as *(&arr[0]) is the first element in the array.
char arr[10];
arr has type "array of 10 chars" and &arr is "pointer to array of 10 chars." , *(&arr) is the same as arr, and has the same type, i.e, base address.
&arr[0] will yield a pointer that points to the first element address.
a, *(&a), &a[0] are same (base address of array a/ address of the first element of array a).