#include <stdio.h>
int main()
{
int a[][3] = {1, 2, 3, 4, 5, 6};
int (*ptr)[3] = a;
printf("%d %d \n ", (*ptr)[1], (*ptr)[2]);
++ptr;
printf("%d %d\n", (*ptr)[1], (*ptr)[2]);
ptr++;
printf("%d %d\n", (*ptr)[1], (*ptr)[2]);
return 0;
}
can anyone explain why in first printf, (*ptr)[1],(*ptr)[2] is giving 2,3 as output?
isn't (*ptr)[1] output should be 4 and (*ptr)[2] output should 0?
is it means that (*ptr)[1] is equal to ptr[0][1] and
(*ptr)[2] means ptr[0][2]?
int (*ptr)[3] defines a pointer to an array of 3 elements.
Hence the access (*ptr)[1] refers to the 2nd element of the array where ptr is pointing now (in eg. it points to location contatining 2). Think of it as a matrix. Ptr points to the row (in eg it will point to the location containing 4).
Now about ptr++. Compiler knows that ptr is pointing to an array of 3 int elements. So the step ptr++ increments the pointer by 3 * sizeof(int). In our matrix analogy, ptr is now pointing to next row.
yes your view of "is it means that (*ptr)[1] is equal to ptr[0][1] and (*ptr)[2] means ptr[0][2]? " is correct
First of all, you need to keep in mind that
int a[][3] = {1, 2, 3, 4, 5, 6};
is the same as
int a[2][3] = {{1, 2, 3}, {4, 5, 6}};
and
int (*ptr)[3] = a;
is the same as
int (*ptr)[3] = &a[0];
Now, (*ptr)[1] first dereferences ptr leading to the first subarray. Then, [1] gets the second element from the first subarray which is 2. Similarly, (*ptr)[2] first dereferences ptr leading to the first subarray. Then, [2] gets the third element from the first subarray which is 3.
Next,
++ptr;
increments ptr which implies that now, it points to the address of the second subarray. So now, (*ptr)[1] first dereferences ptr leading to the second subarray. Then, [1] gets the second element from the second subarray which is 4. Similarly, (*ptr)[2] first dereferences ptr leading to the second subarray. Then, [2] gets the third element from the second subarray which is 5.
Now,
ptr++;
further increments ptr which means that it now points to a memory addess past the second subarray or the 2D array. After this, dereferncing the pointer as in (*ptr)[1] and (*ptr)[2] invokes Undefined Behavior as you are reading invalid memory addresses past the array.
Finally,
is it means that (*ptr)[1] is equal to ptr[0][1] and (*ptr)[2] means ptr[0][2]?
Yes. Correct.
Related
I don't understand the difference in the t and p pointers. The t pointer gives the same output when printing t and *t only when using **t I get the value.
What's the difference between them?
The code is:
int main()
{
int B [2][3] = {
{2, 3, 6},
{4, 5, 8}
};
int *p = B;
int (*t)[3] = B;
printf ("%d\n", p);
printf ("%d\n", t);
printf ("%d\n", *p);
printf ("%d\n", *t);
printf ("%d\n", **t);
return 0;
}
Output is:
6422000
6422000
2
6422000
2
Comments have addressed the importance of using the correct format specifiers, but here are a couple of other points to consider:
point 1:
The declaration: int *p = B; should generate a compile time warning. This is because int *p is a simple pointer to int, as such it should only be set to point to the address of (&) a single int. But B does not represent an int.
For illustration, it is instructive to see the variations of warnings for the following 3 incorrect ways of initializing p with B. Each starts off with the phrase:
_"warning: incompatible pointer types initializing `int *` with an..."_:
int *p = B;//...expression of type 'int [2][3]'
int *p = &B;//...expression of type 'int (*)[2][3]'
int *p = &B[0]//...expression of type 'int (*)[3]'
Note the incompatible pointer types at the end of each warning. Each of them is specific, providing the programmer hints how to address the potential problem.
The following initializes *p with the address of a single int and generates no warning
int *p = &B[0][0];//assigning address of p to the location of a single integer value.
point 2:
The following declaration/assignment:
int (*t)[3] = B;
creates t as a pointer to an array of 3 int, and points t to the first instance (row) of 3 int in B where B is defined as:
int B [2][3] = {{2, 3, 6}, {4, 5, 8}};
Because t is defined in this way it is flexible in the way it can be used in that it is pointable to any array of 3 int i.e. it does not matter how many rows B has, or to which row t is pointed. Example, given the following arrays:
int B[5][3] = {{1,2,3}, {4,5,6}, {7,8,9}, {10,11,12}, {13,14,15}};
int A[3] = {0}; //A simple array of 3 int all set to 0
The following declarations can be made:
int (*t)[3] = NULL; //points to nothing
t = B; //points to location of 1st element of 1st row in B
t = &B[1]; //points to location of 1st element of 2nd row in B
t = &B[4]; //points to location of 1st element of 5th row in B
t = &A; //points to location of 1st element of A
Writing int *p = B; isn't a good idea but anyway, it puts the address of the very first element of B, 2 into p. So, p outputs the address(6422000) and *p outputs 2. All good till here.
What is t? It's a pointer to an array, B. What will happen when you print it, you'll get the address to B, which is always also the address of it's very first element, which happens to be 6422000. So, what will happen when you dereference t? You'll get and array, B in this case, which will then decay into a pointer and give you the memory address. And the memory address of B is 6422000. And **t will dereference the dereferenced array. The deference array is B, which will decay into the pointer, 6422000 in this case and that will be dereferenced again, giving 2.
Basically:
p: Address of the very first element of B, 2.
*p: Dereferenced p, in this case 2.
t: Address to B. Address of an array is also the address of it's very first element, equivalent to p.
*t: Dereferences into B, B will decay into it's very first element's pointer, equivalent to p.
**t: Dereferenced *t, which is 2.
Note: I know, the first element of B is {2, 3, 6}, not 2. I refer to 2 as "the very first element". That's inaccurate but for the purpose of explanation, I was forced to use the terminology.
For the following code:
#include <stdio.h>
int main()
{
int a[][3] = {1, 2, 3, 4, 5, 6};
int (*ptr)[3] = a;
printf("%d %d ", (*ptr)[1], (*ptr)[2]);
++ptr;
printf("%d %d\n", (*ptr)[1], (*ptr)[2]);
return 0;
}
what should it print? I am expecting:
2 3 3 4
but the output is:
2 3 5 6
I am expecting the output as 2 3 3 4
because initially the ptr is pointing to the first row of double dimensional array a[][3]. Therefore (*ptr)[1] of first printf will give us 2, like wise (*ptr)[2] will give us 3. But after the ++ptr line it will start pointing to the second element of the first row of a[][3]. Therefore (*ptr)[1] of second line should now give us 3 and likewise (*ptr)[2] should give us 4.
ptr is of type int (*)[3]:
int (*ptr)[3]
The type of ptr specifies how the pointer airthmetic is going to be performed on ptr.
For the following more general case:
int *p;
// ...
int (*ptr)[N] = p;
ptr += M; // same address as p[M * N]
Incrementing the pointer in M results in an address increment of M * N * sizeof(int) and not just M * sizeof(int) as you may have expected.
This is how pointer arithmetic works, because the type of the elements ptr points to is int [N] and not int.
After the statement ++ptr; is executed, ptr points to the third element of a. The increment is done in steps of three elements of type int instead of a single one, that is, in your case, N = 3.
Let's go through this line by line.
int a[][3] = {1, 2, 3, 4, 5, 6};
a has the type "array of array of 3 int". This line is equivalent to
int a[][3] = {{1, 2, 3}, {4, 5, 6}}; /* alternate */
It is clearer with this alternate line that a is an array of arrays. This will help with understanding the next lines.
int (*ptr)[3] = a;
ptr has the type "pointer to array of 3 int". Because of array-to-pointer decay, ptr will point to the first array in a (int (*ptr)[3] = &a[0]).
printf("%d %d ", (*ptr)[1], (*ptr)[2]);
Dereferencing ptr gives a[0], so this will print
2 3
++ptr;
This seems to be where you are confused. Incrementing a pointer to an element makes the pointer point to where the next element would lie if they were in an array. In this case, the current element pointed to and the next element after that are in an array (the element being an array of 3 ints, not a single int). So incrementing the pointer makes it point to the next array of 3 ints (which happens to be a[1]).
printf("%d %d\n", (*ptr)[1], (*ptr)[2]);
Now that we know that ptr points to a[1], we can see that (*ptr)[1] is equivalent to a[1][1], which is 5; and that (*ptr)[2] is equivalent to a[1][2], which is 6. So now the total output is:
2 3 5 6
(*ptr)[3] is a pointer to an array of three elements. Below is an analysis of your program.
#include<stdio.h>
int main()
{
int a[][3] = {1, 2, 3, 4, 5, 6};
int (*ptr)[3]=a;
/* First note ptr is a pointer to an array of three integers
* If you had written it like
* int (*ptr)[3];
* ptr=&a[0];
* ,it would have been more obvious.
* But here, you have the freedom to use it interchangeably
*/
printf("%d %d ", (*ptr)[1], (*ptr)[2]);
/* Remember ptr is &a[0], so *ptr is dereferencing &a[0] to gets its value
* However, since ptr is a pointer to an array, its value itself is an array
* So you need to give the index like (*ptr)[1] & (*ptr)[2] to get the second and third values
* (Mind the count starts with zero)
* In essence you are doing,
* printf("%d %d ", *((*ptr)+1*4*8),*((*ptr)+2*4*8)); // 4bytes=4*8 bits
* Here '*ptr' will be substituted with a[0],the starting address an 12 byte block ( 3 integers * 4 bytes per integer)
*/
++ptr;
/* Above step can be written as
* ptr=ptr+1;
* This is pointer arithmetic, so '1' above should be considered as 1 block
* Or in layman's terms move pointer to the next 12byte block.
* In other words advance ptr by (12*8) bits so that it now points to &a[1]
*/
printf("%d %d\n", (*ptr)[1], (*ptr)[2]);
/* Follow the same steps for the first print with ptr is &a[1]
*/
return 0;
}
Why is it that when *q is used in 1D array it gives the value in the array whereas *p in 2D array gives an address instead. Isn't *pointer_name supposed to tell what is stored, so why is output an address instead of 40 (the value in array)?
#include<stdio.h>
int main(){
int a[3][4] = {
{40, 1, 2, 3} ,
{4, 5, 6, 7} ,
{8, 9, 10, 11}
};
int (*p)[4] = a;
int b[4] = {3,4,8,5};
int *q = b;
printf("%d, %d",*q, *p);// output- 3, 10485040
return 0;
}
Because p is a pointer to an array. When you dereference p the array will decay to a pointer to the first element. Doing *p and &(*p)[0] is equivalent (and also equivalent to &a[0][0]).
If you want to print the first element then you need to dereference both pointers, i.e. **p.
2D array means an array of arrays! so each slot of first row in the 2D array should have the address of another array.
for instance if you have an array a[2][3] , the a[0] value is the address of the first slot of an array with size 4. and a[1] like so etc .
Code:
int a = 5;
int *ptr;
ptr = &a;
printf("%d",*ptr);
printf("\n%d",*(ptr++));
printf("\n%d",(*ptr)++);
printf("\n%d",++(*ptr));
Output:
5
5
1638268
1638268
and I am expecting the output to be:
5
junk
5
7
Sory, my pointer and operator precedence concept is very bleak. Can't understand this simple ouput.
The first is obviously 5, just dereferencing a pointer
Still five because the postfix operator returns the pointer preincrement
3 and 4 are junk because the pointer no longer points to memory that has been assigned
If you want the second to act like you expected and print junk you can use the prefix ++ instead
int a = 5;
int *ptr;
ptr = &a;
printf("%d",*ptr); // 5 as you expected.
printf("\n%d",*(ptr++)); // 5, because the pointer is incremented after this line
printf("\n%d",(*ptr)++); // Not 5 because pointer points to another location.
printf("\n%d",++(*ptr)); // Pointer already changed, no longer pointing at 5.
int a = 5;
int *ptr;
ptr = &a; // ptr is the address of the int 5
printf("%d",*ptr); // dereferences ptr, which points to in 5
printf("\n%d",*(ptr++)); // increments ptr by one, so ptr not points to
// an int one over from wherever int 5 is in memory
// but return ptr before incrementing and then dereference it
// giving int 5
printf("\n%d",(*ptr)++); // dereference ptr, which is now one int over from 5 thanks
// to the last line, which is garbage, try
// to increment garbage by 1 after printing
printf("\n%d",++(*ptr)); // dereference ptr, which is now one int over from 5,
// try to increment garbage by one before printing
*ptr just gives the value at the location which is nothing but value of a.
*(ptr++) is equivalent to (*ptr) and then (ptr += 1) because of post increment, so first it gives the value which is used by printf and then increments the pointer so now it is pointing to junk memory .
(*ptr)++ is equivalent to (*ptr) and then (*ptr += 1), so it takes the value at junk memory and increments it.
++(*ptr) is equivalent to (*ptr) += 1 so it increments the value at the junk location, now you can see the effect of undefined behavior so you don't get the last incremented value plus one, but got the same value as the last one because of undefined behavior. On my compiler I got the last incremented value plus one.
int f(int b[][3]);
int main()
{
int a[3][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
f(a);
printf("%d\n", a[2][1]);
}
int f(int b[][3])
{
++b;
b[1][1] = 1;
}
3x3 => 9 elements contained in the 2-D array a. When it's passed, then b will contain the the base address of the a. If suppose base address is 1000 then ++b how does it to 3 locations and not 9 locations ahead? Are we doing typecasting when the variable a is passed to b[][3] as only the three elements?
How does b[1][1] correspond to the address of 8 and not 5?
We can't do incrementing or decrementing in an array as array is a const pointer, but how is that they are incrementing ++b as its an array?
The function heading
int f(int b[][3])
is a nothing more than a confusing way to write (and is exactly equivalent to)
int f(int (*b)[3])
The type of b is "pointer to three-element array of int". When you increment the b parameter you adjust it to point to the next three-element array of int -- now it points to {4,5,6}. Then b[1] indexes once more and gives you the array {7,8,9} and finally b[1][1] gives you the oneth element of that array, namely 8.
C multidimensional arrays are really linear, except that there is syntactic sugar to do the arithmetic correctly.
so with b[][3], it excepts a 1-D array and implicitly translates b[i][j] --> b[3*i+j]
++b works as follows: (++b)[i][j] = ORIGINAL_b[i+1][j]. So in your case, you are accessing ORIGINAL_b[1+1][1] = ORIGINAL_b[2*3+1] = ORIGINAL_b[7] (the 8th element)
Note: this is in stark contrast to the dynamic malloc version (in **b, b is a array of pointers)
How is b[1][1] corresponds to the address of 8 and not address of 5?
This is expected behavior:
int f(int b[][3])
{
//at this point b[0][0] is 1, b[1][1] is 5
++b;
//now b[0][0] is 4, b[1][1] is 8
b[1][1]=1;
}
The pointer has incremented to point to the next memory slot, which is the second slot of array a. Basically:
b -> a[0]
++b -> a[1]