Why does a 3D array print address after being dereferenced twice? Please help me understand the code posted below, (assume that the array begins at location 1002).
int main()
{
int a[2][3][4]={
{
1,2,3,4,
4,5,6,7,
9,1,1,2
},
{
2,1,4,7,
6,7,8,9,
0,0,0,0
}
};
printf("%u %u %u %u\n",a,*a,**a,***a); //a == *a == **a, all print address 1002. Why?
}
**a has type int * and points to the first int in the 3D array
*a has type int (*)[4] and points to the first row of the 3D array
a has type int (*)[3][4] and points to the first 2D array in the 3D array
&a has type int (*)[2][3][4] and points to the whole 3D array
So they are all pointers that point to the same address. It's just that the type of the pointer is different. The following code may help illustrate this point.
int main( void )
{
int a[2][3][4]={ 1,2,3,4, 4,5,6,7, 9,1,1,2, 2,1,4,7, 6,7,8,9, 0,0,0,0 };
int *ptrInt; // pointer to an int
int (*ptrArray1)[4]; // pointer to an array of ints
int (*ptrArray2)[3][4]; // pointer to a 2D array of ints
int (*ptrArray3)[2][3][4]; // pointer to a 3D array of ints
ptrInt = **a;
ptrArray1 = *a;
ptrArray2 = a;
ptrArray3 = &a;
printf( "%p %p\n", ptrInt , ptrInt + 1 );
printf( "%p %p\n", ptrArray1, ptrArray1 + 1 );
printf( "%p %p\n", ptrArray2, ptrArray2 + 1 );
printf( "%p %p\n", ptrArray3, ptrArray3 + 1 );
}
Note: I left out the inner braces in the array initialization specifically to demonstrate that the inner braces are optional. Best practice would have all of the inner braces.
Typical output from this code is shown below. I've added comments to show the difference between the two pointers as a decimal number.
0x17b00 0x17b04 // 4 bytes, hence pointer to an int
0x17b00 0x17b10 // 16 bytes, pointer to int[4]
0x17b00 0x17b30 // 48 bytes, pointer to int[3][4]
0x17b00 0x17b60 // 96 bytes, pointer to int[2][3][4]
Note that when you add 1 to any pointer, the size of the object is added to the pointer. For example, if you have an int * and you add 1 to that pointer, the value of the pointer will increase by 4 because sizeof(int) == 4. (Yes, that assumes that ints are 32-bits, thank you.)
So by adding 1 to a pointer, you can determine the size of the object that the pointer points to. That gives you a clue about the type of the pointer from the compiler's point of view. In the example above, notice that adding 1 to ptrArray1 changes the pointer by 16. That's because ptrArray1 points to an object of size 16, specifically it points to an array of 4 ints.
Just so that we're all completely confused, allow me to say that the following line of code will print the number 8. I chose 8 since it only appears once in the array, so you can tell where it's coming from.
printf( "%d\n", ptrArray3[0][1][1][2]);
Notice that it appears that I'm using ptrArray3 as a 4-dimensional array. This is why pointers to multidimensional arrays are so confusing in C. When you convert an array to a pointer, the pointer has one less dimension than the array. But when you use the pointer with array syntax, you use it as though it had one more dimension.
So for example, start with a 2D array
int array[4][100];
The corresponding pointer is a pointer to a 1D array
int (*ptr)[100] = array;
But you can use that pointer like a 2D array
ptr[2][100] = 6;
That is the basis for all of the confusion, and the reason that pointer-to-array is a seldom used feature in C.
a has the type array of size 2 of arrays of size 3 of arrays of size 4 of int.
*a has the type array of size 3 of arrays of size 4 of int.
**a has the type array of size 4 of int.
All three arrays when decayed to corresponding pointers have the same value because they point to the same location in memory.
Try the following Code:
int main()
{
int a[2][3][4]={
{
{1,2,3,4},
{4,5,6,7},
{9,1,1,2}
},
{
{2,1,4,7},
{6,7,8,9},
{0,0,0,0}
}
};
printf("%u %u %u u%",a,*a,**a,***a);//how a == *a == **a print address 1002 please help me to understand ?
}
The reason it was returning the address was because you didn't declare your 3d array properly at all. The above is the corrected code, try it out and let us know how it goes
Related
I'm playing with OnlineGDB compiler in order to understand how pointers work in C.
First, I ran the following code and got the output I expected:
int *array1[] = {1,4,3,4};
int main()
{
printf("%d \n", array1[0+1]);
printf("%d", array1[1+1]);
return 0;
}
Output was:
4
3
Secondly, I ran the following code - And I can't understand its output:
int *array1[] = {1,4,3,4};
int main()
{
printf("%d \n", array1[0]+1);
printf("%d", array1[1]+1);
return 0;
}
Output:
5
8
It seems like I'm adding 4 to the value from the array, but why? (each element in the array is consisted from a byte).
Thanks!
It seems like I'm adding 4 to the value from the array, but why?
No, each element of the array is an int * because you declared the array that way:
int *array1[] = {1,4,3,4};
That says array1 is an array whose values have type pointer to int. Remove the * if you want an array of int, like:
int array1[] = {1,4,3,4};
When you add or subtract from pointer types, the value changes by some multiple of the size of the type that the pointer refers to. An int on your system is probably 4 bytes, so an expression like array1[0]+1 gets the int * stored in array[0] and increments it, so it increases by sizeof(int).
(each element in the array is consisted from a byte).
Even if you had declared your array as an array of int rather than an array of int *, the size of an int is probably not 1 byte. int is typically 4 bytes long, but size depends on the compiler and target system.
With
int *array1[] = {1,4,3,4};
you are defining tan array of pointers to integers.
So every element of that array, even if initialized with what appear to be integer values, are actually pointers, that are addresses.
If you had deferenced those pointers you would probably have caused a segmentation fault. But fortunately you simply printed them, even if using %d instead of %p: a choice that according to C standard could have caused undefined behavior. Anyway in your case the pointers were converted to integers, and the printed values were the expected ones. Exactly like if the array was an array of integers.
In the second example you pushed it further: you added 1 to the array elements. But since they are pointers, then pointers arithmetics is applied. Meaning that pointer + N = pointer + N * sizeof(*pointer). In this case, since sizeof(int) is 4:
array[0] + 1 =
= 1 + sizeof (array[0]) =
= 1 + sizeof( int ) =
= 1 + 4 = 5
While going through an example of pointers I came across a line which was *p[5] declares p as an array of 5 pointers while (*p)[5] declares p as a pointer to an array of five elements. I didn't understand the difference between them.
Could anyone explain it with an example?
1. int (*p)[5]
is called a Pointer to an Array(Array Pointer). We can declare a pointer that can point to whole array instead of only one element of the array.This pointer is useful when talking about multidimensional arrays.
In this example p is pointer that can point to an array of 5 integers.
/*Pointer to an array*/
#include<stdio.h>
int main(void)
{
int *ptr; /*can point to an integer*/
int (*p)[5];/*can point to an array of 5 integers*/
int arr[5];
ptr=arr;/*points to 0th element of arr*/
p=&arr;/*points to the whole array arr*/
printf("ptr=%p,p=%p\n",ptr,p);
ptr++;
p++;
printf("ptr=%p,p=%p\n",ptr,p);
return 0;
}
Output:
ptr=0012FEAC,p=0012FEAC
ptr=0012FEB0,P=0012FEC0
Here ptr is pointer that points to 0th element of array arr,while p is pointer that points to the whole array arr.The base type of ptr is int while base type of p is ‘an array of 5 integers’.
We know that pointer arithmetic is performed relative to the base size,so if we write p++ then the pointer will be shifted forward by 20 bytes.
2. Now coming to *p[5]:
This is called Array of Pointers(Pointer Array)
Correct syntax is datatype *arrayname[size];
We can declare an array that contains pointers as its elements.Every element of this array is a pointer variable that can hold address of any variable of appropriate type.
/*Array of pointers*/
#include<stdio.h>
int main(void)
{
int *p[5];
int i,a=5,b=10,c=15;
p[0]=&a;
p[1]=&b;
p[2]=&c;
for(i=0;i<3;i++)
{
printf("p[%d]=%p\t",i,p[i]);
printf("*p[%d]=%d\n",i,*p[i]);
}
return 0;
}
Output:
p[0]=0012FEB4 *p[0]=5
p[1]=0012FEA8 *p[1]=10
p[2]=0012FE9C *p[2]=15
I hope this explanation along with examples will clear your concepts.
Hope this is helpful :)
The order of evaluation differs. *p[3] resolves to *(p[3]) but not (*p)[3]. Also note that *p is equivalent to p[0]. Therefore, ...
*p[3] ⇔ *(p[3]) ⇔ (p[3])[0] ⇔ p[3][0]
(*p)[3] ⇔ (p[0])[3] ⇔ p[0][3]
Assuming you have an array of arrays, the difference is shown below:
A pointer is like a sticky note; you write on it where you put the actual object.
An array is a box with equal compartments. It can store objects of the same type.
You have three balls.
An array of three pointers is a box that contains three stickers. Each sticker tells where each ball is located (they might not be all in the same place).
A pointer to an array of three elements is a sticky note that tells where to find the box. The box contains all tree balls.
Let us see if this helps ,in short, assuming int
1) int *p[3]
int *p1 = &i;
int *p2 = &j;
int *p3 = &k;
Instead of the above 3 separate pointers, I can have an array of pointers as int *p[3]. Each element in the array can point to i,j, and k, all are ints
2) int (*p)[3]
int array[3];
If I want a pointer which points to this array which have 3 elements, the pointer declaration will be int (*p)[3]. This is a pointer pointing to array
#include<stdio.h>
int main()
{
int arr[] = {10, 20, 30, 40, 50, 60};
int *ptr1 = arr;
int *ptr2 = arr + 5;
printf("Number of elements between two pointer are: %d.",
(ptr2 - ptr1));
printf("Number of bytes between two pointers are: %d",
(char*)ptr2 - (char*) ptr1);
return 0;
}
For the first printf() statement the output will be 5 according to Pointer subtraction confusion
What about the second printf() statement, what will be the output?
To quote C11, chapter §6.5.6, Additive operators
When two pointers are subtracted, both shall point to elements of the same array object, or one past the last element of the array object; the result is the difference of the subscripts of the two array elements.
So, when you're doing
printf("Number of elements between two pointer are: %d.",
(ptr2 - ptr1));
both ptr1 and ptr2 are pointers to int, hence they are giving the difference in subscript, 5. In other words, the difference of the address is counted in reference to the sizeof(<type>).
OTOH,
printf("Number of bytes between two pointers are: %d",
(char*)ptr2 - (char*) ptr1);
both ptr1 and ptr2 are casted to a pointer to char, which has a size of 1 byte. The calculation takes place accordingly. Result: 20.
FWIW, please note, the subtraction of two pointers produces the result as type of ptrdiff_t and you should be using %td format specifier to print the result.
If you have two pointers of type T that point to elements of the same array then the difference of the pointers yields the number of elements of type T between these pointers
So the first output statement
printf("Number of elements between two pointer are: %d.",
(ptr2 - ptr1));
outputs 5 - the number of elements of type int between pointers ptr1 and ptr2.
It is the so-called pointer arithmetic.
Pointers (char*)ptr1 and (char*)ptr2 have the same values as the original pointers ptr1 and ptr2 but they consider (reinterpret) the memory extent as an array of type char each element of which has size equal to sizeof( char ). In C sizeof( char ) is always equal to 1.
Thus the difference ( char * )ptr2 - ( char * ) ptr1 gives the number of elements of type char that can fit the memory extent. It is evident that
sizeof( char ) is not greater than sizeof( int ). So the same memory extent can accomodate more elements of type char than of type int. If for example sizeof( int ) is equal to 4 then the memory extent can accomodate 5 * sizeof( int ) elements of type char that is 20.
Pointer arithmetics is always in the units of the base type.
In your case you have
int *ptr1 = ...
Then doing ptr1 + 5 will add sizeof(*ptr1) * 5 bytes to the pointer ptr1. Considering that sizeof(*ptr1) (which is the same as sizeof(int)) is 4, then you get 4 * 5 which equals 20 bytes.
Each array element is an int and there are 5 elements between both the pointers. Thus there will be 5*sizeof(int) amount of bytes in between both the pointers.
I'm new in programming and learning about pointers in array. I'm a bit confused right now. Have a look at the program below:
#include <stdio.h>
int fun();
int main()
{
int num[3][3]={23,32,478,55,0,56,25,13, 80};
printf("%d\n",*(*(num+0)+1));
fun(num);
printf("%d\n", *(*(num+0)+1));
*(*(num+0)+0)=23;
printf("%d\n",*(*(num+0)));
return 0;
}
int fun(*p) // Compilation error
{
*(p+0)=0;
return 0;
}
This was the program written in my teacher's notes. Here in the main() function, in the printf() function dereference operator is being used two times because num is pointer to array so first time dereference operator will give pointer to int and then second one will give the value at which the pointer is pointing to.
My question is that when I'm passing the array name as argument to the function fun() then why *p is used; why not **p as num is a pointer to array?
Second thing why *(p+0) is used to change the value of zeroth element of the array; why not *(*(p+0)+0)=0 as in the main() function *(*(num+0)+0) is used to change the value of zeroth element?
The whole thing is very confusing for me but I have to understand it anyway. I have searched about this and found that there is a difference between pointer to array and pointer to pointer but I couldn't understand much.
The trick is the array-pointer-decay: When you mention the name of an array, it will decay into a pointer to its first element in almost all contexts. That is num is simply an array of three arrays of three integers (type = int [3][3]).
Lets analyse the expression *(*(num + 1) + 2).
When you mention num in the expression *(num + 1), it decays into a pointer to its first element which is an array of three integers (type = int (*)[3]). On this pointer pointer arithmetic is performed, and the size of whatever the pointer points to is added to the value of the pointer. In this case it is the size of an array of three integers (that's 12 bytes on many machines). After dereferencing the pointer, you are left with a type of int [3].
However, this dereferencing only concerns the type, because right after the dereferencing operation, we see expression *(/*expression of type int[3]*/ + 2), so the inner expression decays back into a pointer to the first array element. This pointer contains the same address as the pointer that results from num + 1, but it has a different type: int*. Consequently, the pointer arithmetic on this pointer advances the pointer by two integers (8 bytes). So the expression *(*(num + 1) + 2) yields the integer element at an offset of 12 + 8 = 20 bytes, which is the sixth integer in the array.
Regarding your question about the call of fun(), that call is actually broken, and only works because your teacher did not include the arguments in the forward declaration of fun(). The code
int fun(int* arg);
int main() {
int num[3][3] = ...;
...
fun(num);
}
would have generated a compile time error due to the wrong pointer type. The code of your teacher "works", because the pointer to the first array in num is the same as the pointer to the first element of the first array in num, i. e. his code is equivalent to
int fun(int* arg);
int main() {
int num[3][3] = ...;
...
//both calls are equivalent
fun(num[0]);
fun(&num[0][0]);
}
which would compile without error.
This example shows a matrix, pointers to the first integers of arrays, and pointer to pointer
#include<stdio.h>
int fun(int (*p)[3]); /* p is pointer to array of 3 ints */
int main()
{
/* matrix */
int num[3][3]={{23,32,478},{55,0,56},{25,13, 80}};
/* three pointers to first integer of array */
int *pnum[3] = {num[0], num[1], num[2]};
/* pointer to pointer */
int **ppnum = pnum;
printf("%d\n", *(*(num+1)+2));
fun(num);
printf("%d\n", *(*(num+1)+2));
pnum[1][2] = 2;
printf("%d\n", *(*(num+1)+2));
ppnum[1][2] = 3;
printf("%d\n", *(*(num+1)+2));
return 0;
}
int fun(int (*p)[3])
{
p[1][2]=1;
return 0;
}
You do not actually need any pointers to print anything here.
Your int num[3][3] is actually an array of three elements, each of which is an array of three integers. Thus num[0][0] = 23, num[1][1] = 0, and so on. Thus you can say printf("%d", num[0][0]) to print the first element of the array.
Pointer to variable:
Pointer is variable which stores the address( of a variable). Every one know that.
Pointer to Array:
An array is a variable which has the starting point(address) of group of same objects.
And the pointer is a variable which stores the starting point(address) of an Array.
For example:
int iArray[3];
iArray is a variable which has an address value of three integers and the memory is allocated statically. And the below syntax is provided in a typical programming languages.
// iArray[0] = *(iArray+0);
// iArray[1] = *(iArray+1);
// iArray[2] = *(iArray+2);
In the above the iArray is a variable through which we can access the three integer variables, using any of the syntax mentioned above.
*(iArray+0); // Here iArray+0 is the address of the first object. and * is to dereference
*(iArray+1); // Here iArray+1 is the address of the second object. and * is to dereference
So simple, what is there to confuse.
The below lines are for your understanding
int iArray1[3];
int iArray2[3][3];
int *ipArray = 0;
ipArray = iArray1; // correct
ipArray = iArray2[0]; // correct
ipArray = iArray2[2]; // correct
int **ippArray = iArray2; // wrong
As per the above last line, compiler will not take it as a valid assignment. So **p is not used.
Pointer arthmatic cannot be applied on double arrays because of the way memory is allocated.
This question already has answers here:
Is an array name a pointer?
(9 answers)
Closed 8 years ago.
i have often heard that array and pointers can be used interchangeable in some situation but the two does not mean the same thing so what are the circumstances in which we can use array as a pointer and vice versa.
Arrays and pointers are never the same thing.
However, under certain circumstances, an array name in your code will "decay" to a pointer to the first element. That means you lose information about the size of the array since a pointer doesn't know how many elements it points to (technically, it only points at one though you can advance through a contiguous array if you can tell where the end is, such as with a length or sentinel value).
Situations in which arrays do not behave like pointers are (for example):
when you do a sizeof: for the array, it's the size of the entire array, for a decayed pointer, it's the size of the pointer.
when you want to move through an array: with a real array, you must use indexing while you can simply increment the pointer.
Consider the following code:
#include <stdio.h>
void fn (int arr[]) {
printf ("sz = %d\n", sizeof(arr));
printf ("#4 = %d\n", arr[4]);
arr = arr + 1;
printf ("#4 = %d\n", arr[4]);
}
int main (void) {
int x[] = {1,2,3,4,5,6,7,8,9};
printf ("sz = %d\n", sizeof(x));
printf ("#4 = %d\n", x[4]);
//x = x + 1; // Cannot do this
printf ("#4 = %d\n", x[4]);
puts("=====");
fn(x);
return 0;
}
which outputs:
sz = 36
#4 = 5
#4 = 5
=====
sz = 4
#4 = 5
#4 = 6
You can see from that the sizeof is different and you can actually move the pointer whereas the array name is at a fixed location (you'll get an error if you uncomment the line that tries to increment it).
The name of an array behaves pretty much like a pointer to the first element. That is it's value, although it has other attributes that are different.
This is most obvious when calling a function. If you have:
float sum_floats(const float *x, size_t num_values);
you can call it with:
float three[] = { 1.f, 2.f, 3.f };
const float sum = sum_floats(three, sizeof three / sizeof *three);
Note how three in the function call "decays" into &three[0], i.e. a pointer to the first element in the array. Note also how sizeof three still works, since three really is an array.
Inside the function, the array has decayed into const float *, the type of the function's argument, and you can no longer use sizeof to get the size of the caller's array (since the function has no idea that the caller used an array).
Typically an array is a container for a number of elements of the same type, while a pointer is the memory address for a memory location that contains a specific value.
When you declare an array like this:
int arr[] = {1, 2, 3, 4, 5};
printf("%d", *arr); /* will print 1 */
printf("%d", arr[0]); /* will print 1 as well */
/*or*/
int arr[5];
you are allocating memory for 5 integers. Take care that the array name by itself acts as a pointer to the first element in the array.
You can achieve the same thing using pointers:
int* arr = new int[5];