I am learning C programming by myself, and stuck with this practice
int a[] = {5,7,9,11,13};
int *p;
int i = 2;
p = a;
*(p++) = ++i;
printf("%d %d %d %d", a[0], a[i++], *p, *(p+2));
// output: 3 11 7 11
My understanding is that
1.define an array a and initialise it with values 5,7,9,11,13
2.define pointer p
3.define i and initialise it with value 2
4.p points to array a
5.p[1] = 3;
a[0] = 5, a[3] = 11, *p = p[0] = 5, *(p+2) = p[2] = 9
//output: 5 11 5 9
But they are totally wrong !
I may need detailed explanation for this.
Please help me and many thanks!
Your understanding is correct till 3.
4 - p points to the first element of a.
5 - You are using the post increment operator. So p's old value will be used and p will be incremented (meaning p will now point to the second element in a). So this is equivalent to p[0] = i + 1; p = p + 1; i = i + 1;
At this point p is pointing to the second element of a and the first element of a is changed to 3. i is also 3 at this point.
a[0] = 3, a[i++] = a[3] = 11, *p = a[1] = 7, *(p+2) = a[3] = 11.
This is exactly the output you get - See here.
For the line *(p++) = ++i;
This sets the value of a[0] to 3. Note since ++ is after p, it evaluates p = p + 1 after the expression.
a[i++] is a[3] which is 11. Note we start from 0 when counting.
We incremented p in the line *(p++) = ++i; therefore p points to a[1] which is 3.
Lastly *(p+2) means that p now points to a[3] which is 11.
There you have it 3 11 7 11
This line
*(p++) = ++i;
uses a mix of pre- and post-increments. When you have trouble understanding such code, you should rewrite the code so that only a single thing happens in each line.
In this case it can be rewritten to:
i = i + 1; // From ++i which is the pre-increment, i.e. increment first and
// then use the new value
*p = i; // The assignment without pre/post increments
p = p + 1; // From p++ which is the post-increment, i.e. use the current value and
// then increment afterwards
Now you have 3 simple statements that makes it easier to understand the code.
This
int a[] = {5,7,9,11,13};
p = a;
looks like below
---------------------------------
| 5 | 7 | 9 | 11 | 13 |
---------------------------------
0x100 0x104 0x108 ..(lets assume bas address of a is 0x100)
a
p <-- p pints to base address of a
Next when you do like
*(p++) = ++i; /* ++i means 3 */
p++ results in same(post increment rule) address in this expression so 3 got assigned to 0x100 memory location, in the next iteration p points to 0x104 memory location, so now array a looks like below
-----------------------------------------
| 3(5<--old) | 7 | 9 | 11 | 13 |
-----------------------------------------
0x100 0x104 0x108 ..
a |
p <-- p points here
Next when the below printf() executes as below
printf("%d %d %d %d", a[0], a[i++], *p, *(p+2));
lets solve one by one
*(p+2) == *(0x104 + 2*4)
== 11 (prints 11)
And then
*p yields in 7 as p points to 0x104 memory location.
and
a[i++] yields in a[3] i.e 11 but for next expression i becomes 4.
and
a[0] prints 3 as I pointed in above figure. hence it prints
3 11 7 11.
Side note, function parameters are not evaluated in a defined order in C, read this.
Related
The following lines of code work as you'd expect
#include <stdio.h>
int main(void)
{
int n;
int a[5];
int *p;
a[2] = 1024;
p = &n;
/*
* write your line of code here...
* Remember:
* - you are not allowed to use a
* - you are not allowed to modify p
* - only one statement
* - you are not allowed to code anything else than this line of code
*/
/* ...so that this prints 98\n */
printf("a[2] = %d\n", a[2]);
return (0);
}
This prints out a[2] = 1024
Now I was asked to modify this code so that a[2] = 98 gets printed instead. There were a ton of constraints. I couldn't use the variable a anywhere else in the code again and a couple other things. I found a solution online but I don't understand it at all.
#include <stdio.h>
int main(void)
{
int n;
int a[5];
int *p;
a[2] = 1024;
p = &n;
/*
* write your line of code here...
* Remember:
* - you are not allowed to use a
* - you are not allowed to modify p
* - only one statement
* - you are not allowed to code anything else than this line of code
*/
p[5] = 98;
/* ...so that this prints 98\n */
printf("a[2] = %d\n", a[2]);
return (0);
}
So, setting p[5] = 98; results in a[2] = 98 being printed, which is the intended result. I'm fairly new to C programming and pointers in general but I have absolutely no idea why this works the way it does.
This is all about the layout of the stack, the memory where the local variables in your method are stored. Variables are pushed onto the stack, so first the variable n is pushed to the stack, let us assume that it ends up at address 1000 (this is just a fictional address). Since it is an integer it takes up the space of an integer (4 bytes if integers are 32 bits). Then you push the array a to the stack. It will be located next to n.
Since n was placed at address 1000 and took up 4 bytes of memory, then a will be placed at address 1004 (1000 + 4). a is an array of 5 integers, each taking up 4 bytes. So a takes up the space from 1004 to 1024.
Your variable p is an integer pointer, and you set it to point to n. That means that p points to the address 1000 which is the address of n. You then write p[5] in C that is equivalent to the expression *(p + 5). Which basically means take value of the address p + 5. And since p is an integer pointer and each integer takes up 4 bytes, you are essentially asking for the value of address: 1000 + (5 * 4) = 1020
In the array a you stored the value 1024 at index 2, that corresponds to address: 1004 + 2 * 4 = 1012, so when you print the value of a[2] you are printing the value of address 1012. This means that the value you are setting to 98, is not a[2] but a[4].
The reason why I am mentioning this, is that in my case it did not print 98 but 1024. As people have already mentioned you are working with undefined behavior, and although it might work on some setups, it might not work on all.
I can't tell you the answer to your problem. But I can write a program which might, maybe, find the answer to your problem.
Try running this program:
#include <stdio.h>
int main2(int off)
{
int n;
int a[5];
int *p;
a[2] = 1024;
p = &n;
p[off] = 98;
return a[2];
}
int main()
{
int i;
for(i = -5; i <= 5; i++)
if(main2(i) == 98)
printf("the magic offset is %d\n", i);
}
On my computer, with one of my compilers, today, this program prints
the magic offset is 4
That tells me that (on my computer, with that compiler, today) the "solution" to your ridiculous problem would be
#include <stdio.h>
int main()
{
int n;
int a[5];
int *p;
a[2] = 1024;
p = &n;
p[4] = 98;
printf("a[2] = %d\n", a[2]);
}
I'm not even going to try to explain why this works, because the reasons are so obscure, unrepeatable, and meaningless. (See this question's other good answers for more details.) Basically the first program automates the search for a magic offset from p, more or less as you discovered.
And, in fact, under the first compiler I tried it, it didn't even work. Despite using the magic number 4 that the first program discovered, the second program printed a[2] = 1024. That's not too surprising: the relative positions of variables like a, p, and n are not specified by any standard. They're totally up to the compiler. The compiler is perfectly within its rights to arrange them one way in function main2 in my first program, and a completely different way in function main in my second program.
I tried my first program under a different compiler, and it printed
the magic offset is -3
and then crashed with a segmentation fault. But then, under that compiler, when I changed the relevant line in the second program to
p[-3] = 98;
it "worked", printing a[2] = 98 as required.
(And then I tried turning up the optimization level, and it stopped working.)
To be perfectly clear, the fact that my approach did not work under that first compiler, because it failed to arrange things in a consistent or predictable way, does not mean there's anything wrong with that compiler! Quite the contrary: the fault is entirely in the broken programs I wrote, and the broken assignment of yours that motivated them.
Here is an alternative exercise which will teach you something useful about arrays and pointers, without requiring that you "learn" false, unrepeatable facts about how variables are or aren't guaranteed to be arranged in stack frames.
#include <stdio.h>
int main(void)
{
int a[5];
int *p;
a[2] = 1024;
p = &a[4];
/*
* write your line of code here...
* Remember:
* - you are not allowed to use a
* - you are not allowed to modify p
* - only one statement
* - you are not allowed to code anything else than this line of code
*/
/* ...so that this prints 98\n */
printf("a[2] = %d\n", a[2]);
}
This problem has a similar solution — you can easily work it out — but the solution is unique and guaranteed to work, because it depends on well-defined properties of arrays and pointer arithmetic in C, not on accidental details of the stack layout.
It "works" by accident. It relies on n, p, and a being laid out in memory in a specific order (each box represents 4 bytes):
Address Item
------- --------
+---+
0x8000 n: | | p[0]
+---+
0x8004 p: | | p[1]
+---+
0x8008 | | p[2]
+---+
0x800c a: | | a[0] p[3]
+---+
0x8010 | | a[1] p[4]
+---+
0x8014 | | a[2] p[5]
+---+
0x8018 | | a[3] p[6]
+---+
0x801c | | a[4] p[7]
+---+
Some background:
A pointer is any expression whose value is the location of an object or function in a running program's execution environment - essentially, an address. A variable of pointer type stores an address value. However, pointers have associated type semantics - a pointer to int is a different type than a pointer to double, which is a different type than a pointer to struct foo, which is a different type than a pointer to an array of char, etc.
When you add 1 to a pointer value, the result is a pointer to the next object of the pointed-to type immediately following:
char *cp = &some_char;
short *sp = &some_short;
long *lp = &some_long;
+---+ +---+ +---+
some_char: | | <-- cp some_short: | | <-- sp some_long: | | <-- lp
+---+ | | | |
| | <-- cp + 1 | | | |
+---+ +---+ | |
| | <-- cp + 2 | | <-- sp + 1 | |
+---+ | | | |
| | <-- cp + 3 | | | |
+---+ +---+ +---+
| | <-- cp + 4 | | <-- sp + 2 | | <-- lp + 1
+---+ | | | |
... ... ...
This is exactly how array subscripting works - the array subscript operation a[i] is defined as *(a + i) - given a starting address a, offset i elements (not bytes!) from that address and deference the result. Arrays are not pointers; rather, array expressions "decay" to pointers to their first element under most circumstances. But this means you can use the [] subscript operator on pointer variables as well, so if you set p to point to n with
int *p = &n;
then you can apply the [] operator to p and treat it as though it was an array. So, if p == 0x8000 (the address of n), then p + 5 == 0x8014, which is the address of a[2]. Thus, *(p + 5) == p[5] == a[2] == *(a + 2).
But...
This behavior is undefined - it may work, it may not. It may result in garbled output, it may branch into some random subroutine, it may invoke Rogue. Neither the compiler nor the runtime environment are required to handle it in any particular way - any result is equally correct as far as the language is concerned.
We're pretending n is the first element of an array of int when it really isn't, so we're indexing out of bounds with p[1], p[2], etc. We're assuming objects are laid out in a specific order, but the compiler is under no obligation to lay variables out that way. The compiler may optimize things such that p is stored in a register, rather than on the stack.
This is a horrible way to teach pointers. It's unsafe, it's unportable, it's bad practice, it's confusing, it's an atypical use case, it doesn't explain why we use pointers. Whoever gave you this code shouldn't be teaching anyone how to program in C. If they write C for a living they are a menace.
Can some one explain me the logic with respect to the value of the variable b?
#include <stdio.h>
unsigned char buffer[4] = {1,2,3,4}; /* Declare the buffer */
unsigned char* u8GetHeader(void)
{
static int count = 0;
count++; /* incrementing the value of count for every invoke */
if(1 == count)
return &buffer[0];
else
return &buffer[1];
}
int main()
{
unsigned int a , b;
a = (u8GetHeader())[0];
b = (u8GetHeader())[1];
printf("The value of variable a = %d\n",a);
printf("The value of variable b = %d\n",b);
}
This program is a good candidate for working out on paper first and then stepping through the program to see if it matches your expectations.
Let us assume buffer is a global at address 0x1000.
The first call to u8GetHeader returns the address of buffer[0], which is just buffer or 0x1000. You then index it with 0, so you access the number at 0x1000 which is 1.
The second call returns the address of buffer[1], or 0x1001. You index it with 1, so you access the number at 0x1002, which is 3.
Why b gives you 3: Since count is static it will increment on each call. With b = (u8GetHeader())[1]; you call the function a second time so &buffer[1] is returned which is a pointer to {2,3,4} and its second value is 3.
Lets modify your program a little:
int main()
{
unsigned int a , b;
unsigned int *x, *y;
x = u8GetHeader();
y = u8GetHeader();
a = x[0];
b = y[1];
printf("The value of variable a = %d\n",a);
printf("The value of variable b = %d\n",b);
}
The first time the u8GetHeader function is called it returns a pointer to the first element of the array. This gets assigned to the x variable.
Each time after the first call, the u8GetHeader function will return a pointer to the second element. This gets assigned to the y variable.
Now if we "draw" the array and the pointers to the different elements in it it could look like this:
+---+---+---+---+
| 1 | 2 | 3 | 4 |
+---+---+---+---+
^ ^
| |
x y
It should be pretty clear that y is pointing to the value 2. That is y[0] == 2. From this it should also be quite clear that adding 1 to that index (i.e. y[1]) will then get the second element from y, which is the value 3. So y[1] == 3.
Perhaps it is also useful to know that for any array of pointer p and index i, the expression p[i] is exactly equal to *(p + i).
From this we get that y[1] then must be *(y + 1)., and if we add an arrow for y + 1 in the drawing we get:
+---+---+---+---+
| 1 | 2 | 3 | 4 |
+---+---+---+---+
^ ^ ^
| | |
x y y+1
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I have this code from an old exam.
The first print generates 5a9b1740.
And the question is what does the second print generate.
x: unknown since we do not know what *k holds.
y: 35.
z: ffff ffff. WHY?
p: 5c9b1748. WHY?
{
int x = 4;
int y = 15;
int *k = &x;
int z;
int *p;
*k = *k * (*k + 1);
y = x + y;
k = &z;
int a[] = {7,9,3,8};
p = a;
printf("%x\n",(unsigned int)p);
x = *k + 1;
p = p + 2;
z = *p - 4;
printf("%d %d %x %x\n",x,y,z,(unsigned int)p);
}
Edit: Sorry for causing confusion, the first print is 5a9b1740 and second 5c9b1748. Not 5a9b1740,5c961748. Question is edited on that regard.
x: unknown since we do not know what *k holds.
Technically, the value of *k when x = *k + 1; was executed is indeterminate since it points to z and z was uninitialized at that time. This means the value is either unspecified (i.e. it can have any value) or a trap representation (i.e. it doesn't represent a valid value and can trigger a fault if read). If the value happens to be a trap representation then reading invokes undefined behavior.
In some cases reading an uninitialized variable can still be undefined even if it is not a trap representation, however that is not the case here because z had its address taken.
y: 35.
At this point:
*k = *k * (*k + 1);
y = x + y;
k points to x and 4 has the value 4, so the first line is the same as x = 4 * (4 + 1). This sets x to 20, then adding that to the current value of y (15) gives 35.
z: ffff ffff. WHY?
p: 5c9b1748. WHY?
Looking at these lines:
p = a;
p = p + 2;
z = *p - 4;
This first points p to the first element of a, and that pointer has value 5a9b1740 as in the first printf. The next line then points it to 2 elements after that one. Assuming an int is 4 bytes on your system, that means the raw value of the pointer p increased 2 * 4 = 8. So the value of p is now 5a9b1740 + 8 = 5a9b1748.
With p now pointing to the third element of a which has the value 3, the following line sets z to -1. This value is then printed with the %x format specifier which interprets the value as an unsigned int and prints it in hex. Assuming two's complement representation of negative numbers an (again) a 4 byte int, this value has the representation ffffffff. When read as an unsigned int is is this that is printed.
p.s. no 3:
It comes out that, the addresses given in the question are not the actual outcome of a program execution but example values given with the assignment text. So, there is a possible typo: either both addresses would start with 5c9b... or both w/ 5a9b....
p.s. no 2:
Please refer to the comments as well. Just checking the last 2 ~ 4 digits of the addresses, I overlooked the weird address gap b/w the 1st & 2nd results of the print lines.
Let's go line by line:
Line 1:
int x = 4; // x is defined and set to value 4
Line 2:
int y = 15; // y is defined and set to value 15
Line 3:
int *k = &x; // pointer k is set to point x
Line 4:
int z; // z is defined but uninitialized
Line 5:
int *p; // pointer p is defined but uninitialized
Line 7:
*k = *k * (*k + 1);
// k was set to point x (above)
// so, *k = x
// and x = x * (x + 1) => x = 4 * 5 = 20
Line 8:
y = x + y
// y = 20 + 15 = 35
Line 9:
k = &z;
// k is set to point z (but z is still uninitialized)
Line 11:
int a[] = {7, 9, 3, 8};
// array 'a' is defined
Line 12:
p = a;
// p is set to point the first int element of array 'a'
Line 13:
printf("%x\n", (unsigned int)p);
// printing the memory address of p
// same as printing the memory address of array 'a'
Line 14:
x = *k + 1;
// k was set to point z
// but z is still uninitialized
// so, x = z + 1 is unpredictable so far
// x is, whatever the value z plus 1
Line 15:
p = p + 2;
// p was set to point first integer element of array 'a'
// so, after p = p + 2, p = address of 'a' + 2 * sizeof(int)
// since sizeof(int) = 4 bytes, p is now address(a) + 8
// p is now pointing to the third element of array 'a'
// that is, p is pointing to '3'; *p = 3
Line 16:
z = *p - 4;
// p was set to point third element of array 'a'
// *p was '3'
// so, z = *p - 4 means z = 3 - 4 = -1
Line 17:
printf("%d %d %x %x\n", x, y, z, (unsigned int)p);
// x is, what ever the value of z plus 1
// y is 35
// z is -1; its hex representation if ffff ffff
// p is address of array a plus 2; p = &a[0] + 2
// that is; p is now, address of array 'a' + 2 * sizeof(int)
p.s. Yes, I had nothing else to do today.
{
int x = 4;
int y = 15;
int *k = &x;
int z;
int *p;
*k = *k * (*k + 1); /* x = x * (x+1) i.e. 20 */
y = x + y; /* y = 20 + 15 i.e. 35 */
k = &z; /* fine, though the content is not initialised */
int a[] = {7,9,3,8};
p = a;
printf("%x\n",(unsigned int)p);
x = *k + 1; /* x = z +1 which is unknown because content of z still not initialised */
p = p + 2; /* pointing to 3 now */
z = *p - 4; /* z= 3 - 4 ; i.e. -1 */
printf("%d %d %x %x\n",x,y,z,(unsigned int)p);
}
The result prints a signed integer (z) as unsigned, which in this case results in the representation of -1 in the twos-complement hex representation, but shown as unsigned, i.e. "ffff ffff" in 32bit.
I initially was confused by z not being intialised, but it turns out to be irrelevant.
It seems to me that the value of p would not really have been predictable.
Judging from the first print being "5a9b1740", the value should be bigger by the size of two ints, i.e. "5a9b1748" on most systems. But that does not match the output you show (before or after your edit to the question; please note 5c9b1748-5a9b1740=2000008 and 5c961748-5a9b1740=1FB 0008. Neither can be explained with the shown code. For some reason people fail to see the large difference and focus only on the few least significant nibbles...)
If those two values come from different runs of the program, then it could explain the difference with intentional randomisation. (Thanks to Gerhardh for making me look for an explanation.)
This is blatantly undefined behavior. The compiler is allowed to lay out variables in any order it likes, even leave variables without backing store (it just keeps the value in a register, sees it isn't ever used, or can deduce it's value each time it is used and doesn't require storing it, ever. You can not legally point outside the referenced object by adding to the pointer. For a rather dumb compiler (or no optimization whatsoever) the above might be right. Or it might not.
For examples of the above, compile some program with e.g. gcc -O2 -g and debug it. When single-stepping the debugger will often jump around seemingly at random in the source, skip some statements altogether, tell you some variables have been optimized out, and others.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
int* p = malloc(sizeof(int)*5);
*p = 1, *(p+1) = 2, *(p+2) = 3, *(p+3) = 4, *(p+4) = 5;
for(int i = 0; i < 5; i++){
//what exactly is going on in these lines?
printf("%d %p\n", (*p++)++, p);
//printf("%d %p\n", (*++p)++, p);
//printf("%d %p\n", ++(*p++), p);
//printf("%d %p\n", ++(*++p), p);
}
What is operator precedence in these lines above?
If we add parentheses to all potentially ambiguous expressions in the code above, we get:
int p = malloc((sizeof (int)) * 5);
(((((*p) = 1), ((*(p+1)) = 2)), ((*(p+2)) = 3)), ((*(p+3)) = 4)), ((*(p+4)) = 5);
for(int i = 0; i < 5; i++){
printf("%d %p\n", (*(p++))++, p);
}
That is:
sizeof has higher precedence than *
unary * has higher precedence than =, = has higher precedence than ,, and , is left associative
postfix ++ has higher precedence than unary *
There is no pointer arithmetic in your code because there are no pointers. int p declares an int.
That's why *p = 1 doesn't even compile, so this code doesn't actually do anything.
If you fix that, the code still doesn't do anything because the (*p++)++, p part in your printf call has undefined behavior: It's modifying p and reading from p without an intervening sequence point.
*p = 1, *(p+1) = 2, *(p+2) = 3, *(p+3) = 4, *(p+4) = 5;
is equivalent to (in that case, not always)
*p = 1; *(p+1) = 2; *(p+2) = 3; *(p+3) = 4; *(p+4) = 5;
concerning
printf("%d %p\n", (*p++)++, p);
the order of the execution or the arguments is indeterminate, so same for the result
P.S. next you put a code, please check before it is possible to compile it without error (int ptr = malloc(sizeof(int)*5); must be int * p = malloc(sizeof(int)*5);)
Let's draw some pictures. After the first two lines, you have the following:
+---+---+---+---+---+
| 1 | 2 | 3 | 4 | 5 |
+---+---+---+---+---+
^
|
|
|
+---+
p: | |
+---+
The expression (*p++)++ is parsed as (*(p++))++ and is evaluated as follows:
p++ - evaluate to the current value of p (&p[0]); as a side effect,
update `p` to point to the next object in the sequence (&p[1])
*p++ - dereference the result of `p++` (p[0])
(*p++)++ - evaluate to the current value of the thing `p` points to
(1), then increment the value of that thing.
After that expression has been evaluated, our state is now
+---+---+---+---+---+
| 2 | 2 | 3 | 4 | 5 |
+---+---+---+---+---+
^
|
+---+
|
+---+
p: | |
+---+
The expression (*++p)++ is parsed as (*(++p))++ and evaluates as:
++p - evaluate to the current value of p plus 1 (&p[2]), which gives us
the address of the next object in the sequence;
update p to point to the next object (&p[2])
*++p - dereference the result of ++p (p[2])
(*++p)++ - evaluate to the current value of thing following what p currently
points to (3), and as a side effect increment that thing.
After that expression has been evaluated, our state is now
+---+---+---+---+---+
| 2 | 2 | 4 | 4 | 5 |
+---+---+---+---+---+
^
|
+-------+
|
+---+
p: | |
+---+
You should be able to work out the other two. However...
The statement
printf("%d %p\n", (*p++)++, p);
invokes undefined behavior, because you're both trying to read p and update it without an intervening sequence point. The value that gets printed for p may or may not reflect the update from p++ or ++p. Function arguments are not guaranteed to be evaluated in any particular order.
I created a pointer to pointer and a int array, but when I try to access the array via my pointer to pointer, it skips some elements and moves by two elements at a time (eg: from 1 to 3).
Here is my code:
int main(void) {
int c=10;
int p[5]={2,3,5,6,8};
int *x;
int **y;
x=p;
y=&p;
printf("p value is %d and p points to %d",p,&p);
printf("\n x is %d \n",x[1]);
printf("\n y is %d \n",y[0]);
return 0;
}
When I print y[1] it will print 5 instead of 3 and y[2] is printed as 8. I can't think of the reason. Can any one help me on this? Pointer x is is working fine and moves along the correct elements as x[0]=2, x[1]=3, x[5]=5.
also can any one explain why i get same value for p and &p
Okay, this question has been answered and an answer has been accepted, but even the accepted answer does not explain the weird results the original poster was seeing: why do y[1] and y[2] print 5 and 8? Here is the explanation.
Original poster: What output do you get from the following statements?
printf ("Size of integer: %zu\n", sizeof (int));
printf ("Size of pointer: %zu\n", sizeof (int*));
I'm going to bet that the output is:
Size of integer: 4
Size of pointer: 8
In other words, I'm guessing that you're compiling on a 64-bit machine where the size of an integer is 4 bytes and the size of a pointer is 8 bytes. Based on that assumption, here's what is happening.
p is an array. With a few exceptions, when used in any expression, the array's name "decays" to a pointer to its first element. Any time you access the value of p, therefore, it will yield the address of its first element.
&p is one of those exceptions to the rule about arrays "decaying" to pointers. The address-of operator, when applied to an array's name, returns a pointer to the entire array--not a pointer to a pointer to the first element of the array.
What this means is that p and &p have the same value, but they are semantically very different. You will get the same value when you print:
printf("p value is %p and p points to %p", p, &p); // use %p and not %d for addresses
However, this does not mean that p and &p refer to the same thing. p is the address of first element of the array, i.e., &p[0]. On the other hand, &p is the address of the entire array of 5 integers.
So when you define x and y as follows:
int* x = p;
int** y = &p;
x is assigned a pointer to the first element of the array; y is assigned a pointer to the entire array. This is an important difference!
There is, moreover, a mismatch between how y is declared, and the value you're assigning to it. &p is of type int (*) [5]; a pointer to an array of 5 int. y is merely a pointer to a pointer to a single int. Your compiler should give you a warning about this mismatch. Mine does:
Warning: incompatible pointer types assigning to 'int**' from 'int (*) 5'
This mismatch explains the weird results while printing values of y[1] and y[2]. Let's look at what's going on with the values.
As you know, array subscripts are offsets from the beginning of the array:
x[0] == *(x + 0)
So x[0] yields the first element of the array, i.e., 2. Similarly
x[1] == *(x + 1)
But x is a pointer to int. So what is actually happining in the addition x + 1? Remember how pointer arithmetic works. Adding an integer to a pointer means you're actually adding that integer times the size of the element pointed to. In this case:
x + 1 == x + (1 * sizeof(int))
Since sizeof(int) is 4 on your system, the value of x[1] is the next integer in the array, which is 3.
So then, when you print y[0], how is this evaluated?
y[0] == *(y + 0)
Hence, the value that is at the address pointed to by y, i.e., at the address of p, is printed. This is the first element of p, hence you get the result 2.
What happens when you print y[1]?
y[1] == *(y + 1)
But what is y? It is a pointer to a pointer to an int. So when you add 1 to y, the way pointer arithmetic works is it again adds 1 * the size of the type of the element pointed to.
y + 1 == y + (1 * sizeof (int*))
The size of an int* is 8 bytes, not four! So every time you increment y by 1, you're incrementing it by 8 bytes, or the size of two integers. Hence, when you dereference that value, you are getting not the next integer in the array, but the integer that is two away.
To explain more clearly: Let us assume that the array begins at element 1000. Then, because each int takes four bytes, the following is the case:
Address Element
-----------------------
1000 2
1004 3
1008 5
1012 6
1016 8
p == &p == x == y == 1000
*x == *y == 2
When you add 1 to x, you are adding 1 * sizeof(int), i.e., you are actually adding 4. So you get 1004, and *(x + 1), or x[1], gives you 3.
But when you add 1 to y, you are adding 1 * sizeof(int*), i.e., you are actually adding 8. So you get 1008, and *(y + 1) gives you the element at address 1008, or 5.
This explains the output you are getting. This is NOT, however, a reasonable way to code. You should not expect that the size of a pointer is always going to be 8 bytes. You should not assign an int (*) [] to an int**. You should not dereference a pointer to a pointer to an int and expect to get an int result. And always heed compiler warnings.
This at least gives a clean compilation and uses %p to print pointers:
#include <stdio.h>
int main(void)
{
int p[5]={2,3,5,6,8};
int *x = p;
int **y = &x;
printf("p value is %p and the address of p is %p and p points to %d\n", (void *)p, (void *)&p, *p);
printf("x[1] is %d\n", x[1]);
printf("y[0] is the address %p\n", (void *)y[0]);
printf("y[0][0] is %d\n", y[0][0]);
return 0;
}
Sample output (Mac OS X 10.8.4, GCC 4.8.1, 64-bit compilation):
p value is 0x7fff5a1a54d0 and the address of p is 0x7fff5a1a54d0 and p points to 2
x[1] is 3
y[0] is the address 0x7fff5a1a54d0
y[0][0] is 2
Remember array name can easily decays into pointer to first element in most expressions.
p[] array in memory is like (addresses are assumption):
p
200 204 208 212 216
+----+----+----+----+---+
| 2 | 3 | 5 | 6 | 8 |
+----+----+----+----+---+
▲ ▲ ▲ ▲ ▲
| | | | |
p p+1 p+2 p+3 p+3
After x = p;, x also pointer to first element.
p
200 204 208 212 216
+----+----+----+----+---+
| 2 | 3 | 5 | 6 | 8 |
+----+----+----+----+---+
▲ ▲ ▲ ▲ ▲ ▲
| | | | | |
| p p+1 p+2 p+3 p+3
|
x
+----+
| 200|
+----+
In expression y = &p; , &p is pointer of array of type int(*)[5] and y is int**. (you must getting a warning (or error) compile with -Wall).
Read: Difference between &p and p
Because value-wise both p and &p are same so address value of y is also same as p.
p
200 204 208 212 216
+----+----+----+----+---+
| 2 | 3 | 5 | 6 | 8 |
+----+----+----+----+---+
▲ ▲ ▲ ▲ ▲ ▲
| | | | | |
| p p+1 p+2 p+3 p+3
|
x y
+----+ +----+
| 200| | 200|
+----+ +----+
int* int**
Your first printf:
printf("p value is %d and p points to %d",p,&p);
Should be written as:
printf("p value is %p and p points to %p", (void*)p, (void*)&p);
// ^ ^
Use %p instead of %d because you are printing addresses also typecast to void* is necessary because %p expects void*. As I said value-wise p and &p are same both addresses are same.
Second printf:
printf("\n x is %d \n", x[1]);
Outputs: 3 as x points to first element in array x[1] == *(x + 1) == 3 (in my figures x + 1 == 204).
Third printf:
printf("\n y is %d \n", y[0]);
Note y type is int** so y[0] == *(y + 0) = *y value stored at y type of *y is int*.
So again because y[0] is int* you should use %p instead of %d.
But the above printf statement prints value of first element that is: 2.
Similarly y[1] prints 3 and y[2] prints 5.
Edit
When I print y[1] it will print 5 instead of 3 and y[2] is printed as 8.
No, It outputs as I explained above Check #codepade where sizeof(int) == sizeof(int*) probably in your system sizeof(int*) = twice of sizeof(int) (64-bit compiler) so when you add one you address next to next location.
As #WhozCraig commented: Try y = &x; You may have better luck. And print anything you're passing that should be a "pointer" with %p.
Correct your code.
I think you code cann't compile successfully.
The type of &p is char (*p)[10], but the type of y is char **,
cannot convert from 'char (*)[10]' to 'char **'